在前面介绍JVM的类加载中比如Field和Method的解析之前,都时要县创建一个ResourceMark对象,那么我们今天介绍下ResourceMark这个类。
- class ResourceMark: public StackObj {
- const ResourceMarkImpl _impl;
- // 构造方法
- ResourceMark(ResourceArea* area, Thread* thread) :
- _impl(area),
- _thread(thread),
- _previous_resource_mark(nullptr)
- {
- if (_thread != nullptr) {
- assert(_thread == Thread::current(), "not the current thread");
- _previous_resource_mark = _thread->current_resource_mark();
- _thread->set_current_resource_mark(this);
- }
- }
- public:
- ResourceMark() : ResourceMark(Thread::current()) {}
- explicit ResourceMark(Thread* thread)
- : ResourceMark(thread->resource_area(), thread) {}
- explicit ResourceMark(ResourceArea* area)
- : ResourceMark(area, DEBUG_ONLY(Thread::current_or_null()) NOT_DEBUG(nullptr)) {}
-
- void reset_to_mark() { _impl.reset_to_mark(); }
- };
- 复制代码
ResourceMark的实现类ResourceMarkImpl构造函数和方法
- class ResourceMarkImpl {
- ResourceArea* _area;
- ResourceArea::SavedState _saved_state; // ResourceArea的快照
-
- public:
- explicit ResourceMarkImpl(ResourceArea* area) :
- _area(area),
- _saved_state(area)
- {
- _area->activate_state(_saved_state);
- }
- explicit ResourceMarkImpl(Thread* thread)
- : ResourceMarkImpl(thread->resource_area()) {}
- };
- 复制代码
SavedState是保存ResourceArea当前使用状态的快照。
- class SavedState {
- friend class ResourceArea;
- Chunk* _chunk;
- char* _hwm;
- char* _max;
- size_t _size_in_bytes;
-
- public:
- SavedState(ResourceArea* area) :
- _chunk(area->_chunk),
- _hwm(area->_hwm),
- _max(area->_max),
- _size_in_bytes(area->_size_in_bytes)
- {}
- };
- 复制代码
ResourceMarkImpl的析构函数
在ResouceMark对象是在栈上分配,所以它在生命周期结束后,也会调用 ResourceMarkImpl的析构函数,从而调用reset_to_mark执行重置ResouceArea到分配内存空间之前的快照状态,然后调用deactivate_state将_nesting将1.
- ~ResourceMarkImpl() {
- reset_to_mark();
- _area->deactivate_state将(_saved_state);
- }
- void reset_to_mark() const {
- _area->rollback_to(_saved_state);
- }
- 复制代码
reset_to_mark调用reset_to_mark函数,最终通过调用ResourceArea的 rollback_to函数并传入之前保存的内存资源快照_saved_state。
- void rollback_to(const SavedState& state) {
- assert(_nesting > state._nesting, "rollback to inactive mark");
- assert((_nesting - state._nesting) == 1, "rollback across another mark");
- if (UseMallocOnly) {
- free_malloced_objects(state._chunk, state._hwm, state._max, _hwm);
- }
- if (state._chunk->next() != nullptr) {
- assert(size_in_bytes() > state._size_in_bytes,
- "size: " SIZE_FORMAT ", saved size: " SIZE_FORMAT, size_in_bytes(), state._size_in_bytes);
- set_size_in_bytes(state._size_in_bytes);
- state._chunk->next_chop();
- } else {
- assert(size_in_bytes() == state._size_in_bytes, "Sanity check");
- }
- _chunk = state._chunk; // Roll back to saved chunk.
- _hwm = state._hwm;
- _max = state._max;
-
- // Clear out this chunk (to detect allocation bugs)
- if (ZapResourceArea) {
- memset(state._hwm, badResourceValue, state._max - state._hwm);
- }
- }
- 复制代码
释放当前Chunk后面的Chunk资源
next_chop调用chop释放当前Chunk的后面连接的Chunk的内存空间,可以是通过delete去释放空间.
- void Chunk::next_chop() {
- _next->chop();
- _next = NULL;
- }
-
- void Chunk::chop() {
- Chunk *k = this;
- while( k ) {
- Chunk *tmp = k->next();
- // 清除当前的Chunk的内存
- if (ZapResourceArea) memset(k->bottom(), badResourceValue, k->length());
- delete k; // Free chunk (was malloc'd)
- k = tmp;
- }
- }
- 复制代码
- class ResourceArea: public Arena {
- friend class VMStructs;
- public:
- ResourceArea(MEMFLAGS flags = mtThread) :
- Arena(flags) DEBUG_ONLY(COMMA _nesting(0)) {}
- ResourceArea(size_t init_size, MEMFLAGS flags = mtThread) :
- Arena(flags, init_size) DEBUG_ONLY(COMMA _nesting(0)) {}
- 复制代码
Arena类的主要Field
- class Arena : public CHeapObj<mtNone> {
- protected:
- MEMFLAGS _flags; // 追踪内存的标识
- Chunk *_first; // 第一个分配的chunk
- Chunk *_chunk; // 当前 chunk
- char *_hwm, *_max; // 高水位 and 当前chunk的最大水位
- 复制代码
MEMFLAGS是内存种类的枚举,主要是以下几个内存存储的类别
- define MEMORY_TYPES_DO(f)
- f(mtJavaHeap, "Java Heap") // Java 堆
- f(mtClass, "Class") // java的class对象
- f(mtThread, "Thread") // 线程对象
- f(mtThreadStack, "Thread Stack")
- f(mtCode, "Code") // 生成的字节码
- f(mtGC, "GC")
- f(mtGCCardSet, "GCCardSet") // G1使用的卡表
- f(mtCompiler, "Compiler")
- f(mtJVMCI, "JVMCI")
- f(mtInternal, "Internal")
- 复制代码
Chunk是分配内存资源管理者
Chunk是通过_next指针链接形成单向链表, _len记录当前Chunk的大小
- class Chunk: CHeapObj<mtChunk> {
- private:
- Chunk* _next; // next指针指向下一个,形成链表
- const size_t _len; //当前Chunk的大小
- }
- 复制代码
Arena构造函数初始化
- Arena::Arena(MEMFLAGS flag) : _flags(flag), _size_in_bytes(0) {
- _first = _chunk = new (AllocFailStrategy::EXIT_OOM, Chunk::init_size) Chunk(Chunk::init_size);
- _hwm = _chunk->bottom();
- _max = _chunk->top();
- MemTracker::record_new_arena(flag);
- set_size_in_bytes(Chunk::init_size);
- }
-
- // 内存大小枚举
- enum {
- #ifdef _LP64
- slack = 40, // [RGV] Not sure if this is right, but make it a multiple of 8.
- #else
- slack = 24, // suspected sizeof(Chunk) + internal malloc headers
- #endif
- tiny_size = 256 - slack, // Size of first chunk (tiny)
- init_size = 1*K - slack, // Size of first chunk (normal aka small)
- medium_size= 10*K - slack, // Size of medium-sized chunk
- size = 32*K - slack, // Default size of an Arena chunk (following the first)
- non_pool_size = init_size + 32 // An initial size which is not one of above
- };
- 复制代码
Arena分配内存资源
- void* Amalloc(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
- x = ARENA_ALIGN(x); // 64位内初对齐
- // 校验内存对齐
- assert(is_aligned(_max, ARENA_AMALLOC_ALIGNMENT), "chunk end unaligned?");
- return internal_amalloc(x, alloc_failmode);
- }
- 复制代码
- void* internal_amalloc(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
- assert(is_aligned(x, BytesPerWord), "misaligned size");
- if (pointer_delta(_max, _hwm, 1) >= x) {
- char *old = _hwm;
- _hwm += x;
- return old;
- } else {
- return grow(x, alloc_failmode);
- }
- }
-
- 复制代码
- void* Arena::grow(size_t x, AllocFailType alloc_failmode) {
- size_t len = MAX2(ARENA_ALIGN(x), (size_t) Chunk::size);
-
- Chunk *k = _chunk; //记录之前的Chunk
- _chunk = new (alloc_failmode, len) Chunk(len);
-
- if (_chunk == NULL) {
- _chunk = k; // 创建 Chunk失败,则恢复之前的Chunk指针
- return NULL;
- }
- if (k) k->set_next(_chunk); // 将新的chunk设置_next指针
- else _first = _chunk;
- _hwm = _chunk->bottom(); //保存chunk的最小地址
- _max = _chunk->top(); // 保存chunk的最大地址
- set_size_in_bytes(size_in_bytes() + len);//设置Arena的所有Chunk的总的字节大小
- void* result = _hwm; // 返回Chunk开始分配的内存的void*指针
- _hwm += x; // 将_hwm加上x,那么就分配了[_hwn,_hwn+x]内存空间,返回result指针指向_hwn加x之前的地址指针
- return result;
- }
- 复制代码
Arena的分配内存是Chunk的链表组成

总结
本文主要分析栈上分配的ResouceMark,利用线程的ResourceArea进行分配前的快照保存以及内存分配,并利息ResourceMarkImpl的析构函数,释放当前Chunk后面分配的内存空间,并恢复分配前的内存快照的状态,