MarkSweepPolicy的初始化: 内存代大小的计算
来源:互联网 发布:类似爱情之只有我知 编辑:程序博客网 时间:2024/05/02 22:41
基于标记-清除思想的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在最后一步并没有创建各内存代管理器, 而只是创建了对应的生成器,这是因为只有内存堆管理器在向操作系统成功申请到所需的内存之后,才能创建所有的内存代管理器.
- MarkSweepPolicy的初始化: 内存代大小的计算
- GenCollectedHeap的Gc策略MarkSweepPolicy
- java计算内存的大小方法
- C++类的实例化后占内存的大小计算
- c++类的实例化后占内存的大小计算
- c++类的实例化后占内存的大小计算
- C++类的实例化后占内存的大小计算
- 内存对齐----#pragma pack的用法及大小的计算
- c++类的实例化后占内存的大小计算
- java计算参数目录大小的递归和迭代实现
- Java计算一个对象占用内存的大小
- C/C++--类占用内存的大小计算
- Java计算一个对象占用内存的大小
- sizeof计算对象所占内存的大小详解
- C/C++--类占用内存的大小计算
- C++ 内存对齐 (计算结构体的大小)
- CPP内存占用和sizeof计算大小的问题
- 计算文件夹的大小
- 十月总结
- ECNA 2013 Stampede! (最大流)
- POJ 2718 Smallest Difference (穷竭搜索)
- spring学习7-PropertySource Abstraction
- centos下搭建NFS服务[笔记]
- MarkSweepPolicy的初始化: 内存代大小的计算
- 关于android开发中涉及到的java知识:集合类(一)
- Struts2-----6、配置Action
- soj 11600 Pick It 矩阵连乘模型 动态规划 acdream 1208 qj的奇怪宝具 noip 2006 energy 能量项链
- 记录5--fedora无法下载音乐视频插件的解决方法
- 关于OJ平台之感
- 【jQuery】jQuery中的Ajax —— 示例
- 第11周项目4-特殊的三位数
- Linux系统之一次性解压多个文件