什么是垃圾收集,为什么需要它,它是如何工作的?
垃圾回收是通过销毁未使用的对象来回收全部运行时内存的过程。每个应用程序都需要内存才能运行。但是,计算机内存是有限的。因此,清除未使用的旧数据以为新数据腾出空间很重要。
垃圾回收的主要目的是通过销毁不包含引用的对象来释放堆内存。当一个对象没有被引用时,它被认为是死的并且不再需要了。这样就可以回收对象占用的内存。
Java内存结构
本机内存– 所有可用的系统内存。
堆– 分配给堆的本机内存部分。这是 JVM 存储对象的地方。这是所有应用程序线程的公共空间。此内存区域的大小可使用 -Xms(最小大小)和 -Xmx(最大大小)选项进行配置。
栈——用来存放局部变量和方法调用栈。每个线程都有它的堆栈。
元空间– 此内存存储类元数据和静态变量。这个空间也是大家共享的。由于元空间是本机内存的一部分,它的大小取决于平台。可以使用 MaxMetaspaceSize 标志配置用于元空间的内存量的上限。
PermGen (Permanent Generation) – 在 Java 7 之前一直存在。从 Java 8 开始,它被 Metaspace 区域所取代。
CodeCache – JIT 编译器编译频繁执行的代码,将其转换为本地机器代码,并缓存它以加快执行速度。这也是本机内存的一部分。
垃圾收集
Java 中的垃圾收集是一个自动过程。程序员不需要选择对象并删除它们。
垃圾收集使用 Mark & Sweep 算法。该算法包括三个阶段:
- Mark标记。第一步,GC 扫描所有对象并标记活动对象(仍在使用的对象)。在这个阶段,程序执行被暂停。此步骤也称为“停止世界”。
- Sweep扫一扫。在这一步,内存被步骤中没有看到的对象占用。
- Compact紧凑。在清理过程中幸存下来的对象被移动到单个连续的内存块中。这减少了堆碎片并使得分配新对象变得更容易和更快。
对象生成
什么是对象生成?
Java 中的垃圾收集器实现了按年龄对对象进行分类的分代垃圾收集策略。
为了优化垃圾收集,堆内存进一步分为四个区域。对象根据它们的年龄(它们在应用程序中使用了多长时间)放置在这些区域中。
- 新生成Young Generation。这是创建新对象的地方。年轻代区域分为三个部分:Eden、S0、S1(Survivor Space)。
- 老一代Old Generation。这里有长寿的物体。
什么是停止世界?
当标记阶段开始时,应用程序停止运行。标记完成后,应用程序恢复其工作。任何垃圾收集都是“停止世界”。
什么是世代假设?
如前所述,生成用于优化标记和扫描阶段。世代假设说:
- 大多数物体不会持续很长时间。
- 如果该物体幸存下来,那么它很可能会永远存在。
- 标记和清扫步骤花费的时间更少,有很多碎屑。也就是说,如果您分析小而多的死对象,标记会更快。
因此,基于生成的垃圾收集算法如下所示:
- 新对象在 Eden 区域中创建。幸存者区域(S0、S1)目前是空的。
- 当 Eden 区域填满时,会发生 Minor GC。Minor GC是对年轻代进行标记和清除操作的过程。
- 在 Minor GC 之后,活动对象被移动到 Survivor 的某个区域(例如,S0)。死物被完全移除。
- 随着应用程序的运行,伊甸园空间充满了新的对象。在下一次 Minor GC 时,年轻代和 S0 区域被清除。这次幸存的对象被移动到区域 S1 并且它们的年龄增加(标记它们在垃圾收集中幸存下来)。
- 在下一次 Minor GC 时,重复该过程。然而,这一次,幸存者的区域被颠倒了。活体移动到 S0 并且它们的年龄增加。伊甸园和 S1 区域被清除。
- Survivor 区域之间的对象被复制一定次数(直到它们在一定数量的 Minor GC 中存活)或只要有足够的空间。然后将这些对象复制到旧区域。
- GC少校。使用 Major GC,对老年代执行标记和清除步骤。Major GC 比 Minor GC 慢,因为老年代主要是活动对象。
使用世代的好处
Minor GC 发生在堆的较小部分(约 2/3 的堆)。标记步骤是有效的,因为该区域很小并且主要由死对象组成。
使用世代的缺点
在任何给定时间,Survivor 空间之一(S0 或 S1)都是空的且未使用。
垃圾收集器类型
串行
使用一个线程。
优点
有效,因为线程之间的交互没有开销。
何时使用
单处理器机器。使用小型数据集。
要启用的标志
-XX:+UseSerialGC
平行
使用多个线程。
优点
多线程加速垃圾收集。
何时使用
最佳性能是首要任务。一秒或更长时间的 GC 暂停是可以接受的。使用中型和大型数据集。适用于在多处理器或多线程硬件上运行的应用程序。
要启用的标志
-XX:+UseParallelGC
内容管理系统
被称为低暂停比例收集器。
优点
最大限度地减少停机时间,这是许多应用程序的大部分内容。但是要完成这项任务,您必须牺牲 CPU 负载,并且通常会牺牲整体吞吐量任务。
何时使用
收集器可能适用于使用大量长寿命数据的应用程序。
要启用的标志
-XX:+UseConcMarkSweepGC
G1(垃圾优先)
并行工作者应用程序的艰苦工作正在进行中。
优点
它既可以用于小型系统,也可以用于具有大量处理器和大量内存的大型系统。
何时使用
当带宽跳过响应时间时,GC Pauses 必须小于一秒。
要启用的标志
-XX:+UseConcMarkSweepGC
垃圾优先
并行应用程序的所有艰苦工作都已完成。
优点
低延迟。
何时使用
响应时间优先。
要启用的标志
-XX:+UseG1GC