前文在介绍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;
}
1.GC线程的创建
当我们用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;
}
2.内存堆的内存申请
内存堆管理器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跨平台设计的初步勾勒)
3.内存代管理器的创建及内存分配
内存堆管理器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;
}
}
至于这些内存代管理器是如何工作的, 笔者将会在后面的博文中对这些内存代管理器的实现一一介绍.