前文在介绍Java对象内存分配的上层接口CollectedHeap时就提过, GenCollectedHeap是一种基于内存分代管理的内存堆管理器实现. 它一方面负责java对象的内存分配, 另一方面还得负责垃圾对象的回收, 而GC策略CollectorPolicy则是它的核心组件.这里,内存堆管理器GenCollectedHeap配置的GC策略实现是GenCollectorPolicy的子类, 目前主要的实现包括: MarkSweepPolicy/ASConcurrentMarkSweepPolicy/ConcurrentMarkSweepPolicy. 当然, 本文只会详细的介绍GenCollectedHeap的初始化, 至于它是如何给Java对象分配内存, 又是如何回收垃圾对象的, 笔者将会在后面的博文中娓娓道来.内存堆管理器GenCollectedHeap的初始化主要包括垃圾回收线程的创建,内存堆内存的申请,以及各内存代管理器的创建和内存分配.
内存堆管理器GenCollectedHeap的初始化代码如下:
/** * 初始化内存堆 */ jint GenCollectedHeap::initialize() { printf("%s[%d] [tid: %lu]: 开始初始化内存堆...\n", __FILE__, __LINE__, pthread_self()); CollectedHeap::pre_initialize(); int i; //内存代的数量 _n_gens = gen_policy()->number_of_generations(); // While there are no constraints in the GC code that HeapWordSize // be any particular value, there are multiple other areas in the // system which believe this to be true (e.g. oop->object_size in some // cases incorrectly returns the size in wordSize units rather than // HeapWordSize). guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize"); // The heap must be at least as aligned as generations. size_t alignment = Generation::GenGrain; //各内存代管理器的生成器 _gen_specs = gen_policy()->generations(); //永久代管理器的生成器 PermanentGenerationSpec *perm_gen_spec = collector_policy()->permanent_generation(); //对齐各内存代的初始大小及最大大小 for (i = 0; i < _n_gens; i++) { _gen_specs[i]->align(alignment); } perm_gen_spec->align(alignment); // If we are dumping the heap, then allocate a wasted block of address // space in order to push the heap to a lower address. This extra // address range allows for other (or larger) libraries to be loaded // without them occupying the space required for the shared spaces. if (DumpSharedSpaces) { uintx reserved = 0; uintx block_size = 64*1024*1024; while (reserved < SharedDummyBlockSize) { char* dummy = os::reserve_memory(block_size); reserved += block_size; } } // Allocate space for the heap. char* heap_address; size_t total_reserved = 0; int n_covered_regions = 0; ReservedSpace heap_rs(0); //为内存堆申请空间 heap_address = allocate(alignment, perm_gen_spec, &total_reserved, &n_covered_regions, &heap_rs); if (UseSharedSpaces) { if (!heap_rs.is_reserved() || heap_address != heap_rs.base()) { if (heap_rs.is_reserved()) { heap_rs.release(); } FileMapInfo* mapinfo = FileMapInfo::current_info(); //当前JVM放弃jar共享 mapinfo->fail_continue("Unable to reserve shared region."); allocate(alignment, perm_gen_spec, &total_reserved, &n_covered_regions, &heap_rs); } } if (!heap_rs.is_reserved()) {//没有申请到足够的内存空间,则终止JVM vm_shutdown_during_initialization("Could not reserve enough space for object heap"); return JNI_ENOMEM; } _reserved = MemRegion((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size())); // It is important to do this in a way such that concurrent readers can't // temporarily think somethings in the heap. (Seen this happen in asserts.) _reserved.set_word_size(0); _reserved.set_start((HeapWord*)heap_rs.base()); size_t actual_heap_size = heap_rs.size() - perm_gen_spec->misc_data_size() - perm_gen_spec->misc_code_size(); _reserved.set_end((HeapWord*)(heap_rs.base() + actual_heap_size)); _rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions); set_barrier_set(rem_set()->bs()); _gch = this; //初始化各内存代管理器 for (i = 0; i < _n_gens; i++) { printf("%s[%d] [tid: %lu]: 开始从内存堆中为内存代[%d]划分%lu bytes的总内存空间...\n", __FILE__, __LINE__, pthread_self(), i, _gen_specs[i]->max_size()); ReservedSpace this_rs = heap_rs.first_part(_gen_specs[i]->max_size(), UseSharedSpaces, UseSharedSpaces); _gens[i] = _gen_specs[i]->init(this_rs, i, rem_set()); heap_rs = heap_rs.last_part(_gen_specs[i]->max_size()); } printf("%s[%d] [tid: %lu]: 开始从内存堆中为永久代划分%lu bytes的总内存空间...\n", __FILE__, __LINE__, pthread_self(), PermSize); _perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set()); clear_incremental_collection_failed(); #ifndef SERIALGC // If we are running CMS, create the collector responsible // for collecting the CMS generations. if (collector_policy()->is_concurrent_mark_sweep_policy()) { //CMS Gc策略 bool success = create_cms_collector(); if (!success) return JNI_ENOMEM; } #endif // SERIALGC return JNI_OK; }
当我们用JVM的工具jstack来查询某一个java进程的所有线程状态的时候, jstack除了dump出Java级线程(java程序创建的)外, 还会打印出JVM级线程,如垃圾回收线程. 当以默认的方式启动JVM时,它的垃圾回收线程.就是:
"GC task thread#0 (ParallelGC)" prio=10 tid=0x000000004bcea000 nid=0x38f2 runnable "GC task thread#1 (ParallelGC)" prio=10 tid=0x000000004bceb800 nid=0x38f3 runnable "GC task thread#2 (ParallelGC)" prio=10 tid=0x000000004bced800 nid=0x38f4 runnable "GC task thread#3 (ParallelGC)" prio=10 tid=0x000000004bcef800 nid=0x38f5 runnable "GC task thread#4 (ParallelGC)" prio=10 tid=0x000000004bcf1000 nid=0x38f6 runnable "GC task thread#5 (ParallelGC)" prio=10 tid=0x000000004bcf3000 nid=0x38f7 runnable "GC task thread#6 (ParallelGC)" prio=10 tid=0x000000004bcf5000 nid=0x38f8 runnable "GC task thread#7 (ParallelGC)" prio=10 tid=0x000000004bcf6800 nid=0x38f9 runnable "GC task thread#8 (ParallelGC)" prio=10 tid=0x000000004bcf8800 nid=0x38fa runnable "GC task thread#9 (ParallelGC)" prio=10 tid=0x000000004bcfa800 nid=0x38fb runnable "GC task thread#10 (ParallelGC)" prio=10 tid=0x000000004bcfc000 nid=0x38fc runnable "GC task thread#11 (ParallelGC)" prio=10 tid=0x000000004bcfe000 nid=0x38fd runnable "GC task thread#12 (ParallelGC)" prio=10 tid=0x000000004bd00000 nid=0x38fe runnable垃圾回收线程就是用来做GC用的,它由SharedHeap来创建,之前说过GenCollectedHeap是SharedHeap的子类. SharedHeap创建GC线程的流程如下:
SharedHeap::SharedHeap(CollectorPolicy* policy_) : CollectedHeap(), _collector_policy(policy_), _perm_gen(NULL), _rem_set(NULL), _strong_roots_parity(0), _process_strong_tasks(new SubTasksDone(SH_PS_NumElements)), _workers(NULL) { if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { vm_exit_during_initialization("Failed necessary allocation."); } _sh = this; // ch is static, should be set only once. if ((UseParNewGC || (UseConcMarkSweepGC && CMSParallelRemarkEnabled) || UseG1GC) && ParallelGCThreads > 0) { printf("%s[%d] [tid: %lu]: 试图创建Gc线程管理调度器(Gc线程数量=%lu)...\n", __FILE__, __LINE__, pthread_self(), ParallelGCThreads); _workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads, /* are_GC_task_threads */true, /* are_ConcurrentGC_threads */false); if (_workers == NULL) { printf("%s[%d] [tid: %lu]: 创建Gc线程管理调度器失败!", __FILE__, __LINE__, pthread_self()); vm_exit_during_initialization("Failed necessary allocation."); } else { printf("%s[%d] [tid: %lu]: 试图初始化Gc线程管理调度器...\n", __FILE__, __LINE__, pthread_self()); _workers->initialize_workers(); } } }GC线程的工作原理将会在介绍GC时进行详细的阐述, 而GC线程的数量主要是由配置参数 ParallelGCThreads决定的, 它的默认值是:
product(uintx, ParallelGCThreads, 0, "Number of parallel threads parallel gc will use")虽然 ParallelGCThreads的默认值为0, 不过JVM会根据当前的GC策略和系统cpu的数量来进行计算调整的, 其计算规则参见源代码:
unsigned int Abstract_VM_Version::nof_parallel_worker_threads( unsigned int num, unsigned int den, unsigned int switch_pt) { if (FLAG_IS_DEFAULT(ParallelGCThreads)) { assert(ParallelGCThreads == 0, "Default ParallelGCThreads is not 0"); // For very large machines, there are diminishing returns // for large numbers of worker threads. Instead of // hogging the whole system, use a fraction of the workers for every // processor after the first 8. For example, on a 72 cpu machine // and a chosen fraction of 5/8 // use 8 + (72 - 8) * (5/8) == 48 worker threads. unsigned int ncpus = (unsigned int) os::active_processor_count(); return (ncpus <= switch_pt) ? ncpus : (switch_pt + ((ncpus - switch_pt) * num) / den); } else { return ParallelGCThreads; } } unsigned int Abstract_VM_Version::calc_parallel_worker_threads() { return nof_parallel_worker_threads(5, 8, 8); } // Does not set the _initialized flag since it is // a global flag. unsigned int Abstract_VM_Version::parallel_worker_threads() { if (!_parallel_worker_threads_initialized) { if (FLAG_IS_DEFAULT(ParallelGCThreads)) { _parallel_worker_threads = VM_Version::calc_parallel_worker_threads(); } else { _parallel_worker_threads = ParallelGCThreads; } _parallel_worker_threads_initialized = true; } return _parallel_worker_threads; }
内存堆管理器GenCollectedHeap在向操作系统申请整个堆内存的时候涉及到两个JVM参数DumpSharedSpaces和UseSharedSpaces, 这两个参数不会同时有效.这里先简单介绍一下DumpSharedSpaces和UseSharedSpaces这两个参数所代表的功能.
当JVM启动时若配置-XX:+DumpSharedSpaces, 则它会去jdk的安装目录下寻找一个名为classlist的文件 (linux下它一般在*/jre/lib/classlist), 这个文件其实就是一个类列表, 它的每一行表示的是一个类的全路径名,JVM会加载每一个类(装载/解析/链接),然后把它们对应的类型描述信息dump到一个名为classes.jsa的文件中((linux下它一般在*/jre/lib/amd64/{client|server}/classes.jsa下),然后JVM退出
当JVM启动时若配置-XX:+UseSharedSpaces,则它会通过内存映射文件的方式把classes.jsa文件的内存加载到自己的JVM进程空间中. classes.jsa对应的这一部分内存空间地址一般在永久代内存地址空间的后面. JVM这么做的目的就是让这个JVM的所有实例共享classlist中所有类的类型描述信息以达到节约物理内存的目标
/** * 给内存堆分配内存空间(新生代+旧生代+永久代) */ char* GenCollectedHeap::allocate(size_t alignment, PermanentGenerationSpec* perm_gen_spec, size_t* _total_reserved, int* _n_covered_regions, ReservedSpace* heap_rs){ const char overflow_msg[] = "The size of the object heap + VM data exceeds the maximum representable size"; printf("%s[%d] [tid: %lu]: 开始为内存堆申请内存空间...\n", __FILE__, __LINE__, pthread_self()); // Now figure out the total size. //内存堆的总大小 size_t total_reserved = 0; //内存堆的总分区数量 int n_covered_regions = 0; //内存页大小 const size_t pageSize = UseLargePages ? os::large_page_size() : os::vm_page_size(); //通过新生代及旧生代来计算内存堆的总大小及总分区数 for (int i = 0; i < _n_gens; i++) { total_reserved += _gen_specs[i]->max_size(); if (total_reserved < _gen_specs[i]->max_size()) { vm_exit_during_initialization(overflow_msg); } n_covered_regions += _gen_specs[i]->n_covered_regions(); } //确保内存堆的大小是内存页的整数倍 assert(total_reserved % pageSize == 0, err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize=" SIZE_FORMAT, total_reserved, pageSize)); //通过永久代来计算内存堆的总大小及总分区数 total_reserved += perm_gen_spec->max_size(); assert(total_reserved % pageSize == 0, err_msg("Perm size; total_reserved=" SIZE_FORMAT ", pageSize=" SIZE_FORMAT ", perm gen max=" SIZE_FORMAT, total_reserved, pageSize, perm_gen_spec->max_size())); if (total_reserved < perm_gen_spec->max_size()) { vm_exit_during_initialization(overflow_msg); } n_covered_regions += perm_gen_spec->n_covered_regions(); // 内存堆还包括数据区和代码区 size_t s = perm_gen_spec->misc_data_size() + perm_gen_spec->misc_code_size(); total_reserved += s; if (total_reserved < s) { vm_exit_during_initialization(overflow_msg); } if (UseLargePages) { //使用大内存页 assert(total_reserved != 0, "total_reserved cannot be 0"); //将内存堆的总大小向上调整为内存页大小的整数倍 total_reserved = round_to(total_reserved, os::large_page_size()); if (total_reserved < os::large_page_size()) { vm_exit_during_initialization(overflow_msg); } } // Calculate the address at which the heap must reside in order for // the shared data to be at the required address. char* heap_address; if (UseSharedSpaces) { //JVM共享jar包 // Calculate the address of the first word beyond the heap. FileMapInfo* mapinfo = FileMapInfo::current_info(); int lr = CompactingPermGenGen::n_regions - 1; size_t capacity = align_size_up(mapinfo->space_capacity(lr), alignment); heap_address = mapinfo->region_base(lr) + capacity; // Calculate the address of the first word of the heap. heap_address -= total_reserved; } else { heap_address = NULL; // any address will do. if (UseCompressedOops) { //使用对象地址压缩 heap_address = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); *_total_reserved = total_reserved; *_n_covered_regions = n_covered_regions; printf("%s[%d] [tid: %lu]: 开始为内存堆向操作系统申请大小为%lu bytes的总内存空间...\n", __FILE__, __LINE__, pthread_self(), total_reserved); *heap_rs = ReservedHeapSpace(total_reserved, alignment, UseLargePages, heap_address); if (heap_address != NULL && !heap_rs->is_reserved()) { // Failed to reserve at specified address - the requested memory // region is taken already, for example, by 'java' launcher. // Try again to reserver heap higher. heap_address = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); printf("%s[%d] [tid: %lu]: 开始为内存堆向操作系统申请大小为%lu bytes的内存空间...\n", __FILE__, __LINE__, pthread_self(), total_reserved); *heap_rs = ReservedHeapSpace(total_reserved, alignment, UseLargePages, heap_address); if (heap_address != NULL && !heap_rs->is_reserved()) { // Failed to reserve at specified address again - give up. heap_address = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); assert(heap_address == NULL, ""); printf("%s[%d] [tid: %lu]: 开始为内存堆向操作系统申请大小为%lu bytes的内存空间...\n", __FILE__, __LINE__, pthread_self(), total_reserved); *heap_rs = ReservedHeapSpace(total_reserved, alignment, UseLargePages, heap_address); } } return heap_address; } } *_total_reserved = total_reserved; *_n_covered_regions = n_covered_regions; printf("%s[%d] [tid: %lu]: 开始为内存堆向操作系统申请大小为%lu bytes的内存空间...\n", __FILE__, __LINE__, pthread_self(), total_reserved); *heap_rs = ReservedHeapSpace(total_reserved, alignment, UseLargePages, heap_address); return heap_address; }源代码中的ReservedHeapSpace实际上就是一种操作内存块的数据结构,它向操作系统申请内存的工作原理如下:
ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large, char* requested_address) : ReservedSpace(size, alignment, large, requested_address, (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), alignment) : 0) { // Only reserved space for the java heap should have a noaccess_prefix // if using compressed oops. protect_noaccess_prefix(size); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix) { initialize(size+noaccess_prefix, alignment, large, requested_address, noaccess_prefix, false); } /** * 向操作系统预定内存空间 */ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix, bool executable) { const size_t granularity = os::vm_allocation_granularity(); assert((size & (granularity - 1)) == 0, "size not aligned to os::vm_allocation_granularity()"); assert((alignment & (granularity - 1)) == 0, "alignment not aligned to os::vm_allocation_granularity()"); assert(alignment == 0 || is_power_of_2((intptr_t)alignment), "not a power of 2"); alignment = MAX2(alignment, (size_t)os::vm_page_size()); // Assert that if noaccess_prefix is used, it is the same as alignment. assert(noaccess_prefix == 0 || noaccess_prefix == alignment, "noaccess prefix wrong"); _base = NULL; _size = 0; _special = false; _executable = executable; _alignment = 0; _noaccess_prefix = 0; if (size == 0) { return; } // If OS doesn't support demand paging for large page memory, we need // to use reserve_memory_special() to reserve and pin the entire region. bool special = large && !os::can_commit_large_page_memory(); char* base = NULL; if (requested_address != 0) { requested_address -= noaccess_prefix; // adjust requested address assert(requested_address != NULL, "huge noaccess prefix?"); } if (special) { //向操作系统申请指定大小的内存,并映射到用户指定的内存空间中 base = os::reserve_memory_special(size, requested_address, executable); if (base != NULL) { if (failed_to_reserve_as_requested(base, requested_address, size, true)) { // OS ignored requested address. Try different address. return; } // Check alignment constraints assert((uintptr_t) base % alignment == 0, "Large pages returned a non-aligned address"); _special = true; } else { // failed; try to reserve regular memory below if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes))) { if (PrintCompressedOopsMode) { tty->cr(); tty->print_cr("Reserve regular memory without large pages."); } } } } if (base == NULL) { // Optimistically assume that the OSes returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. // If the memory was requested at a particular address, use // os::attempt_reserve_memory_at() to avoid over mapping something // important. If available space is not detected, return NULL. if (requested_address != 0) { printf("%s[%d] [tid: %lu]: 开始尝试向操作系统申请大小为%lu bytes的内存空间,并映射到指定的内存起始位置...\n", __FILE__, __LINE__, pthread_self(), size); base = os::attempt_reserve_memory_at(size, requested_address); if (failed_to_reserve_as_requested(base, requested_address, size, false)) { // OS ignored requested address. Try different address. base = NULL; } } else { printf("%s[%d] [tid: %lu]: 开始向操作系统申请大小为%lu bytes的内存空间...\n", __FILE__, __LINE__, pthread_self(), size); base = os::reserve_memory(size, NULL, alignment); } if (base == NULL) return; // Check alignment constraints if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry if (!os::release_memory(base, size)) fatal("os::release_memory failed"); // Reserve size large enough to do manual alignment and // increase size to a multiple of the desired alignment size = align_size_up(size, alignment); size_t extra_size = size + alignment; do { char* extra_base = os::reserve_memory(extra_size, NULL, alignment); if (extra_base == NULL) return; // Do manual alignement base = (char*) align_size_up((uintptr_t) extra_base, alignment); assert(base >= extra_base, "just checking"); // Re-reserve the region at the aligned base address. os::release_memory(extra_base, extra_size); base = os::reserve_memory(size, base); } while (base == NULL); if (requested_address != 0 && failed_to_reserve_as_requested(base, requested_address, size, false)) { // As a result of the alignment constraints, the allocated base differs // from the requested address. Return back to the caller who can // take remedial action (like try again without a requested address). assert(_base == NULL, "should be"); return; } } } // Done _base = base; _size = size; _alignment = alignment; _noaccess_prefix = noaccess_prefix; // Assert that if noaccess_prefix is used, it is the same as alignment. assert(noaccess_prefix == 0 || noaccess_prefix == _alignment, "noaccess prefix wrong"); assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base, "area must be distinguisable from marks for mark-sweep"); assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size], "area must be distinguisable from marks for mark-sweep"); }
这里先不介绍操作系统是如何分配内存的细节,但众所周知,Java是一个号称跨平台的可移植性编程语言,JVM必定在每类操作系统上都有对应的实现,这可能还涉及到更底层的计算机体系架构.(下图是笔者对hotspot跨平台设计的初步勾勒)
内存堆管理器GenCollectedHeap从操作系统成功申请到了内存之后,就会把这些内存交给各内存代管理器去管理.GenCollectedHeap会根据GenCollectorPolicy创建的内存代管理器的生成器去创建对应的内存代管理器:
/** * 根据名字创建对应的内存代管理器(新生代+旧生代) */ Generation* GenerationSpec::init(ReservedSpace rs, int level, GenRemSet* remset) { switch (name()) { case Generation::DefNew: //默认年青代内存管理器 return new DefNewGeneration(rs, init_size(), level); case Generation::MarkSweepCompact: //默认的旧生代内存管理器 return new TenuredGeneration(rs, init_size(), level, remset); #ifndef SERIALGC case Generation::ParNew: //可并行GC的年青代内存管理器 return new ParNewGeneration(rs, init_size(), level); case Generation::ASParNew: //可调整大小及并行GC的年青代内存管理器 return new ASParNewGeneration(rs, init_size(), init_size() /* min size */, level); case Generation::ConcurrentMarkSweep: { //CMS的旧生代内存管理器 assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); CardTableRS* ctrs = remset->as_CardTableRS(); if (ctrs == NULL) { vm_exit_during_initialization("Rem set incompatibility."); } // Otherwise // The constructor creates the CMSCollector if needed, // else registers with an existing CMSCollector ConcurrentMarkSweepGeneration* g = NULL; g = new ConcurrentMarkSweepGeneration(rs, init_size(), level, ctrs, UseCMSAdaptiveFreeLists, (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); g->initialize_performance_counters(); return g; } case Generation::ASConcurrentMarkSweep: { //可调整大小及CMS的旧生代内存管理器 assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); CardTableRS* ctrs = remset->as_CardTableRS(); if (ctrs == NULL) { vm_exit_during_initialization("Rem set incompatibility."); } // Otherwise // The constructor creates the CMSCollector if needed, // else registers with an existing CMSCollector ASConcurrentMarkSweepGeneration* g = NULL; g = new ASConcurrentMarkSweepGeneration(rs, init_size(), level, ctrs, UseCMSAdaptiveFreeLists, (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); g->initialize_performance_counters(); return g; } #endif // SERIALGC default: guarantee(false, "unrecognized GenerationName"); return NULL; } } /** * 根据名字创建对应的内存代管理器(永久代) */ PermGen* PermanentGenerationSpec::init(ReservedSpace rs, size_t init_size, GenRemSet *remset) { // Break the reserved spaces into pieces for the permanent space // and the shared spaces. ReservedSpace perm_rs = rs.first_part(_max_size, UseSharedSpaces, UseSharedSpaces); ReservedSpace shared_rs = rs.last_part(_max_size); if (enable_shared_spaces()) { if (!perm_rs.is_reserved() || perm_rs.base() + perm_rs.size() != shared_rs.base()) { FileMapInfo* mapinfo = FileMapInfo::current_info(); mapinfo->fail_continue("Sharing disabled - unable to reserve address space."); shared_rs.release(); disable_sharing(); } } switch (name()) { case PermGen::MarkSweepCompact: return new CompactingPermGen(perm_rs, shared_rs, init_size, remset, this); #ifndef SERIALGC case PermGen::MarkSweep: guarantee(false, "NYI"); return NULL; case PermGen::ConcurrentMarkSweep: { assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); CardTableRS* ctrs = remset->as_CardTableRS(); if (ctrs == NULL) { vm_exit_during_initialization("RemSet/generation incompatibility."); } // XXXPERM return new CMSPermGen(perm_rs, init_size, ctrs, (FreeBlockDictionary::DictionaryChoice)CMSDictionaryChoice); } #endif // SERIALGC default: guarantee(false, "unrecognized GenerationName"); return NULL; } }至于这些内存代管理器是如何工作的, 笔者将会在后面的博文中对这些内存代管理器的实现一一介绍.