Dan*_*ski 22 java garbage-collection
我经常读到,在Sun JVM中,短期对象("相对较新的对象")可以比长寿命对象("相对较旧的对象")更有效地进行垃圾收集.
Chu*_*Lee 22
大多数Java应用程序创建Java对象,然后相当快地丢弃它们,例如.在方法中创建一些对象然后在退出方法后,所有对象都会死亡.大多数应用程序都采用这种方式,大多数人倾向于以这种方式编写应用程序.Java堆大致分为3个部分,永久性,旧(长寿命)生成和年轻(短期生成)生成.年轻人进一步分为S1,S2和伊甸园.这些只是堆积物.
大多数物体是在年轻人中创造的.这里的想法是,由于物体的死亡率很高,我们很快创造它们,使用它们然后丢弃它们.速度至关重要.当您创建对象时,年轻的gen会填满,直到发生较小的GC.在次要GC中,所有活着的对象都从eden复制并说S2到S1.然后,'指针'在eden和S2上休息.
每个副本都会使对象老化.默认情况下,如果一个对象存活32个副本即.32个小型GC,然后GC表明它将会存在更长时间.因此,它的作用是通过将其转移到老一代来保持它.老一代只是一个很大的空间.当旧的gen填满时,旧的GC会发生完整的GC或主要的GC.由于没有其他空间可供复制,因此GC必须紧凑.这比次要GC慢很多,这就是为什么我们要避免更频繁地这样做.
您可以使用调整tenuring参数
java -XX:MaxTenuringThreshold=16
Run Code Online (Sandbox Code Playgroud)
如果你知道你有很多长寿的物体.您可以打印应用程序的各个年龄段
java -XX:-PrintTenuringDistribution
Run Code Online (Sandbox Code Playgroud)
Tre*_*ald 10
(参见上面对更一般的GC的解释..这个答案为什么新的GC比旧的便宜).
可以更快地清除伊甸园的原因很简单:算法与在伊甸园空间中存活GC的对象数量成正比,与整个堆中的活动对象数量不成比例.即:如果您在伊甸园中的平均物体死亡率为99%(即:99%的物体不能在GC中存活,这不是异常),您只需要查看并复制1%.对于"旧"GC,需要标记/扫描整个堆中的所有活动对象.这要贵得多.
存在“大多数物体在年轻时死亡”的现象。许多对象是在方法内部创建的,并且从不存储在字段中。因此,一旦该方法退出,这些对象就会“死亡”,从而成为下一个收集周期的收集候选对象。
这是一个例子:
public String concatenate(int[] arr) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < arr.length; ++i)
sb.append(i > 0 ? "," : "").append(arr[i]);
return sb.toString();
}
Run Code Online (Sandbox Code Playgroud)
sb一旦方法返回,该对象就会变成垃圾。
通过将对象空间分成两个(或更多)基于年龄的区域,GC 可以更加高效:GC 不会频繁扫描整个堆,而是经常只扫描托儿所(年轻对象区域)——显然,这需要花费大量时间比完整堆扫描花费的时间更少。较旧的对象区域扫描的频率较低。