基於標記-清除思想的GC策略MarkSweepPolicy是串行GC(UseSerialGC)/默認GC(用戶在啓動JVM時未顯示配置GC)的標配,目前只能用於基於內存分代管理的內存堆管理器(GenCollectedHeap)的GC策略, 同時也是GenCollectedHeap的默認GC策略. 當然, GenCollectedHeap還有另外的兩種GC策略, 一是可自動調整各內存代大小的並行標記-清除GC策略(ASConcurrentMarkSweepPolicy); 二是並行標記-清除GC策略(ConcurrentMarkSweepPolicy), 就是通常所說的CMS. 關於這兩種GC策略, 筆者將會在後面的博文中詳細介紹.
GenCollectedHeap是基於內存分代管理的思想來管理整個JVM的內存堆的, 而MarkSweepPolicy作爲GenCollectedHeap的默認GC策略配置, 它的初始化則主要是檢查-調整-確定各內存代的最大,最小及初始化容量. 下圖是MarkSweepPolicy的繼承關係
MarkSweepPolicy的初始化工作主要分爲以下三個步驟:
MarkSweepPolicy::MarkSweepPolicy() {
printf("%s[%d] [tid: %lu]: 開始初始化GC策略: MarkSweepPolicy...\n", __FILE__, __LINE__, pthread_self());
initialize_all();
}
/**
* 初始化GC策略
*/
virtual void initialize_all() {
printf("%s[%d] [tid: %lu]: 開始檢查/調整永久代+新生代+舊生代+內存堆的內存配置..\n", __FILE__, __LINE__, pthread_self());
initialize_flags();
printf("%s[%d] [tid: %lu]: 開始確定內存堆+新生代+舊生代的初始/最小/最大容量..\n", __FILE__, __LINE__, pthread_self());
initialize_size_info();
printf("%s[%d] [tid: %lu]: 開始創建永久代+新生代+舊生代對應的內存管理器的生成器..\n", __FILE__, __LINE__, pthread_self());
initialize_generations();
}
一.內存堆及各內存代的大小配置檢查與調整
1.永久代的大小配置檢查與調整
永久代的內存配置主要是由上層的CollectorPolicy來完成的, 用戶可以通過JVM的啓動參數PermSize和MaxPermSize來設置永久代內存大小.
/**
* 檢查/調整永久代的內存配置
*/
void CollectorPolicy::initialize_flags() {
printf("%s[%d] [tid: %lu]: 開始檢查/調整永久代的內存配置...\n", __FILE__, __LINE__, pthread_self());
if (PermSize > MaxPermSize) {
MaxPermSize = PermSize;
}
PermSize = MAX2(min_alignment(), align_size_down_(PermSize, min_alignment()));
// Don't increase Perm size limit above specified.
MaxPermSize = align_size_down(MaxPermSize, max_alignment());
if (PermSize > MaxPermSize) {
PermSize = MaxPermSize;
}
MinPermHeapExpansion = MAX2(min_alignment(), align_size_down_(MinPermHeapExpansion, min_alignment()));
MaxPermHeapExpansion = MAX2(min_alignment(), align_size_down_(MaxPermHeapExpansion, min_alignment()));
MinHeapDeltaBytes = align_size_up(MinHeapDeltaBytes, min_alignment());
SharedReadOnlySize = align_size_up(SharedReadOnlySize, max_alignment());
SharedReadWriteSize = align_size_up(SharedReadWriteSize, max_alignment());
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment());
assert(PermSize % min_alignment() == 0, "permanent space alignment");
assert(MaxPermSize % max_alignment() == 0, "maximum permanent space alignment");
assert(SharedReadOnlySize % max_alignment() == 0, "read-only space alignment");
assert(SharedReadWriteSize % max_alignment() == 0, "read-write space alignment");
assert(SharedMiscDataSize % max_alignment() == 0, "misc-data space alignment");
if (PermSize < M) {
printf("%s[%d] [tid: %lu]: 永久代配置太小: PermSize(%lu) < M(%lu).\n", __FILE__, __LINE__, pthread_self(), PermSize, M);
vm_exit_during_initialization("Too small initial permanent heap");
}
}
2.新生代的大小配置檢查與調整
新生代大小配置的檢查與調整主要由基於內存分代的垃圾回收策略GenCollectorPolicy負責,通過參數NewSize及MaxNewSize來配置新生代的初始值和最大值.NewRatio是新生代與舊生代的大小比值,SurvivorRatio是新生代中S0/S1/Eden三個內存區的容量比值.
/**
* 檢查/調整永久代+新生代的內存配置
*/
void GenCollectorPolicy::initialize_flags() {
// All sizes must be multiples of the generation granularity.
set_min_alignment((uintx) Generation::GenGrain);
set_max_alignment(compute_max_alignment());
assert(max_alignment() >= min_alignment() &&
max_alignment() % min_alignment() == 0,
"invalid alignment constraints");
/**
* (1).檢查/調整永久代的內存配置
*/
CollectorPolicy::initialize_flags();
// All generational heaps have a youngest gen; handle those flags here.
printf("%s[%d] [tid: %lu]: 開始檢查/調整新生代的內存配置...\n", __FILE__, __LINE__, pthread_self());
/**
* (2).檢查/調整新生代的內存配置
*/
// Adjust max size parameters
if (NewSize > MaxNewSize) {
MaxNewSize = NewSize;
}
NewSize = align_size_down(NewSize, min_alignment());
MaxNewSize = align_size_down(MaxNewSize, min_alignment());
// Check validity of heap flags
assert(NewSize % min_alignment() == 0, "eden space alignment");
assert(MaxNewSize % min_alignment() == 0, "survivor space alignment");
if (NewSize < 3*min_alignment()) { //確保新生代中的三個區(Eden/S0/S1))至少有一個內存單元的容量
vm_exit_during_initialization("Too small new size specified");
}
if (SurvivorRatio < 1 || NewRatio < 1) {
vm_exit_during_initialization("Invalid heap ratio specified");
}
}
NewRatio的默認值是2,SurvivorRatio的默認值是8
product(intx, SurvivorRatio, 8, \
"Ratio of eden/survivor space size") \
\
product(intx, NewRatio, 2, \
"Ratio of new/old generation sizes") \
3.舊生代與內存堆的大小配置檢查與調整
舊生代與內存堆的大小配置的檢查與調整主要由基於兩代內存的垃圾回收策略TwoGenerationCollectorPolicy負責,舊生代的初始大小可由OldSize來配置, 而內存堆的最大值由此時的NewSize與OldSize共同決定
/**
* 檢查/調整永久代+新生代+舊生代+內存堆的內存配置
*/
void TwoGenerationCollectorPolicy::initialize_flags() {
//檢查/調整永久代+新生代的內存配置
GenCollectorPolicy::initialize_flags();
printf("%s[%d] [tid: %lu]: 開始檢查/調整舊生代的內存配置..\n", __FILE__, __LINE__, pthread_self());
//檢查/調整舊生代的內存配置
OldSize = align_size_down(OldSize, min_alignment());
printf("%s[%d] [tid: %lu]: 開始檢查/調整內存堆的內存配置..\n", __FILE__, __LINE__, pthread_self());
//檢查/調整內存堆的內存配置
if (NewSize + OldSize > MaxHeapSize) {
MaxHeapSize = NewSize + OldSize;
}
MaxHeapSize = align_size_up(MaxHeapSize, max_alignment());
always_do_update_barrier = UseConcMarkSweepGC;
// Check validity of heap flags
assert(OldSize % min_alignment() == 0, "old space alignment");
assert(MaxHeapSize % max_alignment() == 0, "maximum heap alignment");
}
二.內存堆及各內存代的容量(最大/初始/最小)
1.確定內存堆的容量
/**
* 確定內存堆容量的配置(最大值/最小值/初始值):
*
* 1.內存堆的初始容量不能小於1M
* 2.內存堆的最小容量不能小於1M
* 3.內存堆的初始容量不能小於新生代大小(NewSize)
* 4.內存堆的最大容量不能小於其最小容量
* 5.內存堆的初始容量不能小於其最小容量
* 6.內存堆的最大容量不能小於其初始容量
*/
void CollectorPolicy::initialize_size_info() {
printf("%s[%d] [tid: %lu]: 開始確定內存堆的初始/最小/最大容量..\n", __FILE__, __LINE__, pthread_self());
// User inputs from -mx and ms are aligned
set_initial_heap_byte_size(InitialHeapSize);
/**
* 如果內存堆的初始容量爲0,則設置爲新生代+舊生代的配置初始容量
*/
if (initial_heap_byte_size() == 0) {
set_initial_heap_byte_size(NewSize + OldSize);
}
set_initial_heap_byte_size(align_size_up(_initial_heap_byte_size, min_alignment()));
//設置內存堆的最小容量
set_min_heap_byte_size(Arguments::min_heap_size());
if (min_heap_byte_size() == 0) {
set_min_heap_byte_size(NewSize + OldSize);
}
set_min_heap_byte_size(align_size_up(_min_heap_byte_size, min_alignment()));
//設置內存堆的最大容量
set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment()));
// Check heap parameter properties
if (initial_heap_byte_size() < M) {
vm_exit_during_initialization("Too small initial heap");
}
// Check heap parameter properties
if (min_heap_byte_size() < M) {
vm_exit_during_initialization("Too small minimum heap");
}
if (initial_heap_byte_size() <= NewSize) {
// make sure there is at least some room in old space
vm_exit_during_initialization("Too small initial heap for new size specified");
}
if (max_heap_byte_size() < min_heap_byte_size()) {
vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");
}
if (initial_heap_byte_size() < min_heap_byte_size()) {
vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");
}
if (max_heap_byte_size() < initial_heap_byte_size()) {
vm_exit_during_initialization("Incompatible initial and maximum heap sizes specified");
}
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap "
SIZE_FORMAT " Maximum heap " SIZE_FORMAT,
min_heap_byte_size(), initial_heap_byte_size(), max_heap_byte_size());
}
}
2.確定新生代的容量
/**
* 確定內存堆+新生代的初始/最小/最大容量
*/
void GenCollectorPolicy::initialize_size_info() {
/**
* (1).確定內存堆的初始/最小/最大容量
*/
CollectorPolicy::initialize_size_info();
// min_alignment() is used for alignment within a generation.
// There is additional alignment done down stream for some
// collectors that sometimes causes unwanted rounding up of
// generations sizes.
// Determine maximum size of gen0
printf("%s[%d] [tid: %lu]: 開始確定新生代的初始/最小/最大容量..\n", __FILE__, __LINE__, pthread_self());
/**
* (2).確定新生代的初始/最小/最大容量
*/
size_t max_new_size = 0;
if (FLAG_IS_CMDLINE(MaxNewSize) || FLAG_IS_ERGO(MaxNewSize)) { //用戶手動配置了新生代的最大容量值
if (MaxNewSize < min_alignment()) {
max_new_size = min_alignment();
}
if (MaxNewSize >= max_heap_byte_size()) {
//配置的新生代最大容量不小於整個內存堆的最大容量,則重新調整新生代的最大容量
max_new_size = align_size_down(max_heap_byte_size() - min_alignment(),
min_alignment());
warning("MaxNewSize (" SIZE_FORMAT "k) is equal to or "
"greater than the entire heap (" SIZE_FORMAT "k). A "
"new generation size of " SIZE_FORMAT "k will be used.",
MaxNewSize/K, max_heap_byte_size()/K, max_new_size/K);
} else {
max_new_size = align_size_down(MaxNewSize, min_alignment());
}
// The case for FLAG_IS_ERGO(MaxNewSize) could be treated
// specially at this point to just use an ergonomically set
// MaxNewSize to set max_new_size. For cases with small
// heaps such a policy often did not work because the MaxNewSize
// was larger than the entire heap. The interpretation given
// to ergonomically set flags is that the flags are set
// by different collectors for their own special needs but
// are not allowed to badly shape the heap. This allows the
// different collectors to decide what's best for themselves
// without having to factor in the overall heap shape. It
// can be the case in the future that the collectors would
// only make "wise" ergonomics choices and this policy could
// just accept those choices. The choices currently made are
// not always "wise".
} else {
//根據新生代與舊生代的配比參數NewRatio來計算新生代的最大容量
max_new_size = scale_by_NewRatio_aligned(max_heap_byte_size());
// Bound the maximum size by NewSize below (since it historically
// would have been NewSize and because the NewRatio calculation could
// yield a size that is too small) and bound it by MaxNewSize above.
// Ergonomics plays here by previously calculating the desired
// NewSize and MaxNewSize.
max_new_size = MIN2(MAX2(max_new_size, NewSize), MaxNewSize);
}
assert(max_new_size > 0, "All paths should set max_new_size");
// Given the maximum gen0 size, determine the initial and
// minimum gen0 sizes.
if (max_heap_byte_size() == min_heap_byte_size()) {
//如果內存堆的最大容量和最小容量相等,則新生代的最小/初始/最大容量都爲其最大容量
set_min_gen0_size(max_new_size);
set_initial_gen0_size(max_new_size);
set_max_gen0_size(max_new_size);
} else {
size_t desired_new_size = 0;
if (!FLAG_IS_DEFAULT(NewSize)) {
// If NewSize is set ergonomically (for example by cms), it
// would make sense to use it. If it is used, also use it
// to set the initial size. Although there is no reason
// the minimum size and the initial size have to be the same,
// the current implementation gets into trouble during the calculation
// of the tenured generation sizes if they are different.
// Note that this makes the initial size and the minimum size
// generally small compared to the NewRatio calculation.
_min_gen0_size = NewSize;
desired_new_size = NewSize;
max_new_size = MAX2(max_new_size, NewSize);
} else {
// For the case where NewSize is the default, use NewRatio
// to size the minimum and initial generation sizes.
// Use the default NewSize as the floor for these values. If
// NewRatio is overly large, the resulting sizes can be too
// small.
//根據新生代與舊生代的配比參數NewRatio來計算新生代的最小容量
_min_gen0_size = MAX2(scale_by_NewRatio_aligned(min_heap_byte_size()), NewSize);
desired_new_size =
MAX2(scale_by_NewRatio_aligned(initial_heap_byte_size()),
NewSize);
}
assert(_min_gen0_size > 0, "Sanity check");
set_initial_gen0_size(desired_new_size);
set_max_gen0_size(max_new_size);
// At this point the desirable initial and minimum sizes have been
// determined without regard to the maximum sizes.
// Bound the sizes by the corresponding overall heap sizes.
set_min_gen0_size(
bound_minus_alignment(_min_gen0_size, min_heap_byte_size()));
set_initial_gen0_size(
bound_minus_alignment(_initial_gen0_size, initial_heap_byte_size()));
set_max_gen0_size(
bound_minus_alignment(_max_gen0_size, max_heap_byte_size()));
// At this point all three sizes have been checked against the
// maximum sizes but have not been checked for consistency
// among the three.
// Final check min <= initial <= max
set_min_gen0_size(MIN2(_min_gen0_size, _max_gen0_size));
set_initial_gen0_size(
MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size));
set_min_gen0_size(MIN2(_min_gen0_size, _initial_gen0_size));
}
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("1: Minimum gen0 " SIZE_FORMAT " Initial gen0 "
SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT,
min_gen0_size(), initial_gen0_size(), max_gen0_size());
}
}
當用戶沒有手動配置新生代的大小容量時,可根據新生代與舊生代的配比來計算新生代的容量
/**
* 根據新生代與舊生代的配比參數NewRatio來計算新生代(最小/初始/最大)容量
*/
size_t GenCollectorPolicy::scale_by_NewRatio_aligned(size_t base_size) {
size_t x = base_size / (NewRatio+1);
size_t new_gen_size = x > min_alignment() ?
align_size_down(x, min_alignment()) :
min_alignment();
return new_gen_size;
}
3.確定舊生代的容量
/**
* 確定內存堆+新生代+舊生代的初始/最小/最大容量
*/
void TwoGenerationCollectorPolicy::initialize_size_info() {
/**
* (1).確定內存堆+新生代的初始/最小/最大容量
*/
GenCollectorPolicy::initialize_size_info();
printf("%s[%d] [tid: %lu]: 開始確定舊生代的初始/最小/最大容量..\n", __FILE__, __LINE__, pthread_self());
/**
* (2).確定舊生代的初始/最小/最大容量
*/
// At this point the minimum, initial and maximum sizes
// of the overall heap and of gen0 have been determined.
// The maximum gen1 size can be determined from the maximum gen0
// and maximum heap size since no explicit flags exits
// for setting the gen1 maximum.
_max_gen1_size = max_heap_byte_size() - _max_gen0_size;
_max_gen1_size = MAX2((uintx)align_size_down(_max_gen1_size, min_alignment()),
min_alignment());
//舊生代沒有配置,或配置錯誤,則通過內存堆及新生代的配置來計算配置舊生代
if (FLAG_IS_DEFAULT(OldSize) || FLAG_IS_ERGO(OldSize)) {
// The user has not specified any value or ergonomics
// has chosen a value (which may or may not be consistent
// with the overall heap size). In either case make
// the minimum, maximum and initial sizes consistent
// with the gen0 sizes and the overall heap sizes.
assert(min_heap_byte_size() > _min_gen0_size, "gen0 has an unexpected minimum size");
//舊生代最小容量
set_min_gen1_size(min_heap_byte_size() - min_gen0_size());
set_min_gen1_size(
MAX2((uintx)align_size_down(_min_gen1_size, min_alignment()),
min_alignment()));
//舊生代初始容量
set_initial_gen1_size(initial_heap_byte_size() - initial_gen0_size());
set_initial_gen1_size(
MAX2((uintx)align_size_down(_initial_gen1_size, min_alignment()),
min_alignment()));
} else {
// It's been explicitly set on the command line. Use the
// OldSize and then determine the consequences.
set_min_gen1_size(OldSize);
set_initial_gen1_size(OldSize);
// If the user has explicitly set an OldSize that is inconsistent
// with other command line flags, issue a warning.
// The generation minimums and the overall heap mimimum should
// be within one heap alignment.
if ((_min_gen1_size + _min_gen0_size + min_alignment()) <
min_heap_byte_size()) {
warning("Inconsistency between minimum heap size and minimum "
"generation sizes: using minimum heap = " SIZE_FORMAT,
min_heap_byte_size());
}
if ((OldSize > _max_gen1_size)) {
warning("Inconsistency between maximum heap size and maximum "
"generation sizes: using maximum heap = " SIZE_FORMAT
" -XX:OldSize flag is being ignored",
max_heap_byte_size());
}
// If there is an inconsistency between the OldSize and the minimum and/or
// initial size of gen0, since OldSize was explicitly set, OldSize wins.
if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size,
min_heap_byte_size(), OldSize)) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 "
SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT,
min_gen0_size(), initial_gen0_size(), max_gen0_size());
}
}
// Initial size
if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size,
initial_heap_byte_size(), OldSize)) {
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 "
SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT,
min_gen0_size(), initial_gen0_size(), max_gen0_size());
}
}
}
// Enforce the maximum gen1 size.
set_min_gen1_size(MIN2(_min_gen1_size, _max_gen1_size));
// Check that min gen1 <= initial gen1 <= max gen1
set_initial_gen1_size(MAX2(_initial_gen1_size, _min_gen1_size));
set_initial_gen1_size(MIN2(_initial_gen1_size, _max_gen1_size));
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr("Minimum gen1 " SIZE_FORMAT " Initial gen1 "
SIZE_FORMAT " Maximum gen1 " SIZE_FORMAT,
min_gen1_size(), initial_gen1_size(), max_gen1_size());
}
}
/**
* 根據新生代/舊生代/內存堆的(最小/初始/最大)容量來確定新生代+舊生代的(最小/初始/最大)容量,如果新生代的
* (最小/初始/最大)容量被調整,則返回true,否則返回false
*/
bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr,
size_t* gen1_size_ptr,
size_t heap_size,
size_t min_gen0_size) {
bool result = false;
if ((*gen1_size_ptr + *gen0_size_ptr) > heap_size) {
if (((*gen0_size_ptr + OldSize) > heap_size) &&
(heap_size - min_gen0_size) >= min_alignment()) {
// Adjust gen0 down to accomodate OldSize
*gen0_size_ptr = heap_size - min_gen0_size;
*gen0_size_ptr =
MAX2((uintx)align_size_down(*gen0_size_ptr, min_alignment()),
min_alignment());
assert(*gen0_size_ptr > 0, "Min gen0 is too large");
result = true;
} else {
*gen1_size_ptr = heap_size - *gen0_size_ptr;
*gen1_size_ptr =
MAX2((uintx)align_size_down(*gen1_size_ptr, min_alignment()),
min_alignment());
}
}
return result;
}
三.內存堆中各內存代生成器的創建
1.舊生代生成器的創建
/**
* 創建永久代內存管理器的生成器
*/
void CollectorPolicy::initialize_perm_generation(PermGen::Name pgnm) {
printf("%s[%d] [tid: %lu]: 開始配置永久代內存管理器的生成器...\n", __FILE__, __LINE__, pthread_self());
_permanent_generation = new PermanentGenerationSpec(pgnm, PermSize, MaxPermSize,
SharedReadOnlySize,
SharedReadWriteSize,
SharedMiscDataSize,
SharedMiscCodeSize);
if (_permanent_generation == NULL) {
printf("%s[%d] [tid: %lu]: 永久內存代配置失敗!.\n", __FILE__, __LINE__, pthread_self());
vm_exit_during_initialization("Unable to allocate gen spec");
}
}
2.新生代與舊生代生成器的創建
/**
* 創建永久代+新生代+舊生代對應的內存管理器的生成器
*/
void MarkSweepPolicy::initialize_generations() {
/**
* (1).創建永久代內存管理器的生成器
*/
initialize_perm_generation(PermGen::MarkSweepCompact);
_generations = new GenerationSpecPtr[number_of_generations()];
if (_generations == NULL)
vm_exit_during_initialization("Unable to allocate gen spec");
/**
* (2).創建新生代內存管理器的生成器
*/
if (UseParNewGC && ParallelGCThreads > 0) {
printf("%s[%d] [tid: %lu]: 新生代內存管理器[ParNewGeneration]的生成器,垃圾回收策略[MarkSweepPolicy],新生代內存[初始大小=%lu, 最大大小=%lu]...\n", __FILE__, __LINE__, pthread_self(), _initial_gen0_size, _max_gen0_size);
_generations[0] = new GenerationSpec(Generation::ParNew, _initial_gen0_size, _max_gen0_size);
} else {
printf("%s[%d] [tid: %lu]: 新生代內存管理器[DefNewGeneration]的生成器,垃圾回收策略[MarkSweepPolicy],新生代內存[初始大小=%lu, 最大大小=%lu]...\n", __FILE__, __LINE__, pthread_self(), _initial_gen0_size, _max_gen0_size);
_generations[0] = new GenerationSpec(Generation::DefNew, _initial_gen0_size, _max_gen0_size);
}
/**
* (3).創建舊生代內存管理器的生成器
*/
printf("%s[%d] [tid: %lu]: 舊生代內存管理器[TenuredGeneration]的生成器,垃圾回收策略[MarkSweepPolicy],舊生代內存[初始大小=%lu, 最大大小=%lu]...\n", __FILE__, __LINE__, pthread_self(), _initial_gen1_size, _max_gen1_size);
_generations[1] = new GenerationSpec(Generation::MarkSweepCompact, _initial_gen1_size, _max_gen1_size);
if (_generations[0] == NULL || _generations[1] == NULL)
vm_exit_during_initialization("Unable to allocate gen spec");
}
MarkSweepPolicy, 顧名思義, 就是標(mark)有用對象,清理(sweep)垃圾對象, 標記對象很"簡單", 但是如何清理對象呢? 在GenCollectedHeap這種基於內存分代管理的內存堆管理器中, 新生代可以通過複製(copy)的方式將active(swep)的對象轉存儲到舊生代, 而舊生代則只能通過壓縮(compact)的方式來進行清理了.MarkSweepPolicy在最後一步並沒有創建各內存代管理器, 而只是創建了對應的生成器,這是因爲只有內存堆管理器在向操作系統成功申請到所需的內存之後,才能創建所有的內存代管理器.