20

最近我一直在阅读 Java 中不同代的对象分配。大多数情况下,新对象在伊甸园(年轻一代的一部分)中分配,然后如果满足以下任何条件,它们就会被提升到老一代。

(1) 对象的年龄达到了任期阈值
(2) 当对象从 Eden(或)另一个幸存者空间(来自)复制时,幸存者空间(to)已满

但也有一种特殊情况,对象直接在老一代中分配,而不是从年轻一代中提升。当我们试图创建的对象很大(可能是几 MB 的数量级)时,就会发生这种情况。


有没有办法知道巨大/巨大物体的大小/限制?我知道 G1 垃圾收集器的巨大对象标准。我只想知道Java 6 之前或中的大小限制。

谢谢你的时间 :)

4

3 回答 3

28

HotSpot JVM 可以在年轻代中分配的对象的最大大小几乎与 Eden 的大小一样大(YoungGen 减去两个 Survivor 空间)。

这就是分配粗略的样子:

  1. 使用线程本地分配缓冲区 (TLAB),如果tlab_top+ size<=tlab_end
    这是最快的路径。分配只是tlab_top指针增量。
  2. 如果 TLAB 快满了,请在 Eden 中创建一个新的 TLAB,然后在新的 TLAB 中重试。
  3. 如果 TLAB 剩余空间不够,但仍然太大而无法丢弃,请尝试直接在 Eden 中分配对象。Eden 中的分配也是使用原子操作的指针增量(eden_top+ size<= eden_end),因为 Eden 在所有线程之间共享。
  4. 如果 Eden 中的分配失败,通常会发生次要收集。
  5. 如果即使在 Young GC 之后 Eden 中也没有足够的空间,则会尝试直接在老年代进行分配。
于 2014-07-07T21:29:43.483 回答
7

您可以使用以下标志设置限制

XX:PretenureSizeThreshold=size

它的默认值是0我假设默认情况下,如果你不设置它,它不会被考虑 value= 0,这意味着默认情况下没有充当阈值的最大值,默认情况下,对象仅根据数量提升GC存活率

热点版本

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

要获取所有 vm 选项(支持),您可以运行

java -XX:+PrintVMOptions -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal  -version

如果未列出,您可以参考热点 vm 选项文档或谷歌特定选项


byte[] array = new byte[300*1024*1024];

for(MemoryPoolMXBean memoryPoolMXBean: ManagementFactory.getMemoryPoolMXBeans()){
    System.out.println(memoryPoolMXBean.getName());
    System.out.println(memoryPoolMXBean.getUsage().getUsed());
}

输出:

$ java -Xmx1500m -Xms1500m -Xmn500m -XX:PretenureSizeThreshold=100000000 -XX:+PrintGCDetails JVMMemoryInspection
Code Cache
393664
PS Eden Space
330301752
PS Survivor Space
0
PS Old Gen
0
PS Perm Gen
2749520
于 2014-07-07T20:00:23.970 回答
4

JVM 标志:

-Xms1G -Xmx1G -Xmn500m -XX:PretenureSizeThreshold=100000000 -XX:+PrintGCDetails

通过将年轻代大小固定为 500MB,eden 大约为 384MB,因此任何大于 384MB 的对象都直接进入 OldGen,而小于 384MB 的对象则在 Eden 本身中分配。您可以在下面找到生成用法

字节[] 数组 = 新字节[400*1024*1024];

PSYoungGen      total 448000K, used 30720K  
    eden space 384000K, 8% used  
    from space 64000K, 0% used  
    to   space 64000K, 0% used      
 ParOldGen       total 536576K, used 409600K  
   object space 536576K, 76% used 

字节[] 数组 = 新字节[300*1024*1024];

 PSYoungGen      total 448000K, used 337920K  
  eden space 384000K, 88% used  
  from space 64000K, 0% used  
  to   space 64000K, 0% used  
 ParOldGen       total 536576K, used 0K 
  object space 536576K, **0% used** 

对于 400MB 分配,eden 使用率为 8%,而 old gen 使用率为 76% 对于 300MB 分配,eden 使用率为 88%,而 old gen 使用率为 0% 所以很明显,所有大小大于 eden 的对象都将直接分配到老一代。

感谢 apangin 和 Jigar 提供宝贵的见解 :)
我认为 -XX:PretenureSizeThreshold 根本没有考虑。

于 2014-07-08T07:27:43.780 回答