Java的垃圾收集
在本教程中,我们将看到Java中的垃圾收集。
我会尝试在图和示例的帮助下解释,而不是理论。
JVM存储器分为三个部分
- 年轻代 Young generation
- 老年代 Old generation
- Metaspace (Perm Gen)
年轻代
顾名思义,年轻一代是新创建的对象被分配的区域。
- 当年轻一代填满时,它会导致少量垃圾收集AKA次要GC。
- 当次要GCS发生时,将从年轻一代中删除死亡对象。
- 如果我们在年轻一代中有很多死亡对象,则未成年的GC将是更快的。
- 所有次要GCS都是"停止世界"事件,因此当发生次要GCS时,应用程序线程也将停止。
让我们了解更多关于对象在年轻一代中分配的信息。
幼年分为3个部分。
- 伊甸园空间
- 幸存者空间S0
- 幸存者空间S1
这是年轻人和旧代的插图。
- 所有新创建的对象都在伊甸园空间中分配。
- 当伊甸园空间完全填充对象时,将发生次要GC。所有未死亡或者未引用的对象将被移动到幸存者空间之一。在我们的情况下,让我们说所有对象都被移动到S0。
- 当再次填充EDEN空间时,EDEN空间中的所有实时对象都将移动到SURVIVOR SPACE S1.
- 一旦对象存活了多个小GC周期,它们将被移动到旧代。我们可以通过MaxTenuringThreshold控制此阈值。实际诱导阈值由JVM动态调整。
让我们尝试在榜样的帮助下演示此行为:我们有以下类,其中我正在为演示创建短暂的物体。
package org.igi.theitroad; import java.math.BigDecimal; public class GCCollectorExample { public static void main(String args[]) { createObjects(); } private static void createObjects() { long count = 0; while(true) { //Creating short-lived objects just for illustration BigDecimal shortLivedBigDecimal1 = new BigDecimal(count++); } } }
运行程序时。
让我们在Visual GC中查看内存分配(VisualVM插件)
如我们所见,我们在S0中有很少的对象,一旦eden空间完全填充,就会将所有引用的对象移动到S1.
老年代
- 它用于持有旧的长幸存物体
- 它通常大于年轻一代。
- 当职业空间完全填充(或者预定义阈值)时,将发生主要GC。它会收回内存并释放空间。
- 通常,主要的GCS比小GC更慢,频繁较少。
如何使用此信息来优化内存?
这取决于应用的性质。
如果我们有很多临时对象,那么将有很多次要GC。
我们可以提供参数xx:newratio = 1,将50%分发给年轻一代,50%到旧。
默认情况下,Newratio = 2因此年轻一代是总堆的1/3.
同样,如果我们有太多的长寿对象,那么我们可能需要通过换高价值的Newratio来增加任期空间的大小。
为什么两个幸存者空间?
你必须想知道为什么我们有2个幸存者空间。
我们有2个幸存者空间来避免内存碎片。
每次将对象从Eden复制到幸存者,我们都会获得空的Eden空间和1个空幸存者空间。
垃圾收集算法
JVM附带了几种年轻和旧代的算法。
有3种类型的算法
系列收集器
它使用单线线执行所有垃圾收集,适用于单个处理器机器的基本应用程序。
平行收集器
它使用多个CPU来执行垃圾收集器。
串行收集器使用1个线程执行GC,但并行GC使用多个线程执行GC,并且当有足够的内存和良好数量的核心时,它很有用。
并发收集器
并发收集器用应用程序线程执行垃圾收集。
它对于具有媒介到大型数据集的应用程序是有用的,并且需要快速响应时间。
我们可以为年轻人和旧代使用不同的GC算法,但我们只能对兼容兼容算法。
例如:我们不能将幼小一代的并行清除对旧的旧作物进行并行标记扫描,因为并行清除不提供CMS中所需的同步。
这是我们可以用于年轻和旧代的垃圾收集器。
Young Collector | Old Collector | JVM options | |
---|---|---|---|
Serial (DefNew) | Serial Mark-Sweep-Compact | -XX:+UseSerialGC | |
Parallel scavenge (PSYoungGen) | Serial Mark-Sweep-Compact (PSOldGen) | -XX:+UseParallelGC | |
Parallel scavenge (PSYoungGen) | Parallel Mark-Sweep-Compact (ParOldGen) | -XX:+UseParallelOldGC | |
Serial (DefNew) | Concurrent Mark Sweep | -XX:+UseConcMarkSweepGC -XX:-UseParNewGC | |
Parallel (ParNew) | Concurrent Mark Sweep | -XX:+UseConcMarkSweepGC -XX:+UseParNewGC | |
G1 | -XX:+UseG1GC |
垃圾收集器后Java 8有很多变化,我将尝试在我的下一个文章中覆盖它们。