针对堆内和堆外分配,涉及到三种主要的垃圾收集器CMS、Parallel Old和G1。
当前我所了解(或者认为自己了解)的情况如下:
- 所有对象(堆内分配)的分配都会向上舍入至8字节边界(或更大的2的幂次方,由
-XX:ObjectAlignmentInBytes
配置)。 - G1
- 对于小于区域大小(1到32MB,可能在堆大小 / 2048附近)的堆内分配,不存在内部碎片,因为没有必要,分配器从不“填补空隙”。
- 对于大于区域大小的堆内分配,将其舍入至区域大小。例如,分配区域大小+1字节非常不幸,将浪费近50%的内存。
CMS唯一找到的相关信息是
Naturally old space PLABs mimic structure of indexed free list space. Each thread preallocates certain number of chunk of each size below 257 heap words (large chunk allocated from global space).
引自http://blog.ragozin.info/2011/11/java-gc-hotspots-cms-promotion-buffers.html。 据我理解,这里的“全局空间”是主要的老年代。
问题:
- 上述陈述是否正确?
- 在CMS中,主要老年代的碎片化属性如何?超过“257个堆字”的分配情况如何?
- Parallel Old GC如何管理老年代?
- Hotspot JVM是否使用系统内存分配器进行堆外分配,还是使用特定的分配器进行重新管理?
更新:讨论线程:https://groups.google.com/forum/#!topic/mechanical-sympathy/A-RImwuiFZE
(Note: The original text was already in Chinese, so I have simply translated it into English without modifying the html tags.)
Unsafe.allocateMemory
并不是大部分内存分配的地方。大部分内存分配发生在此之前(在启动期间),堆的增长是通过单个大内存分配实现的。普通对象分配不会经过该路径,任何其他托管内存区域(例如 JIT 编译的字节码所在的区域)也不会经过该路径。 - Scott Carey