JVM性能优化,第3部分:垃圾回收
![bde3060a34fc29e2898195b9a759ef5a.png](https://img-blog.csdnimg.cn/img_convert/bde3060a34fc29e2898195b9a759ef5a.png)
选择适合您应用程序需求的垃圾收集器
a平台的垃圾收集机制极大地提高了开发人员的生产率,但是实施不当的垃圾收集器会过度消耗应用程序资源。在JVM性能优化系列的第三篇文章中,Eva Andreasson向Java初学者提供了Java平台的内存模型和GC机制的概述。然后,她解释了为什么碎片(而不是GC)是主要的"陷阱"!Java应用程序性能的概述,以及为什么代垃圾回收和压缩是当前管理Java应用程序中的堆碎片的主要方法(尽管不是最创新的方法)。
垃圾回收(GC)是旨在释放不再由任何可访问的Java对象引用的占用内存的过程,并且是Java虚拟机(JVM)动态内存管理系统的重要组成部分。在典型的垃圾回收周期中,将保留所有仍被引用并因此可访问的对象。释放并回收先前引用的对象所占用的空间以启用新的对象分配。
为了了解垃圾回收以及各种GC方法和算法,您必须首先了解有关Java平台的内存模型的一些知识。
垃圾收集和Java平台内存模型
当您-Xmx在Java应用程序的命令行上指定启动选项(例如java -Xmx:2g MyApp:)时,内存将分配给Java进程。该内存称为Java堆(或仅称为heap)。这是专用的内存地址空间,您的Java程序(有时是JVM)创建的所有对象都将分配到该地址空间。随着Java程序不断运行并分配新对象,Java堆(意味着地址空间)将被填满。
最终,Java堆将已满,这意味着分配线程无法为其要分配的对象找到足够大的连续可用内存部分。此时,JVM确定需要进行垃圾收集,并通知垃圾收集器。Java程序调用时也可以触发垃圾回收System.gc()。使用System.gc()不保证垃圾收集。在开始任何垃圾收集之前,GC机制将首先确定启动它是否安全。当所有应用程序的活动线程都处于安全点允许的范围内时,开始进行垃圾收集是安全的,例如,简单地解释说,在正在进行的对象分配过程中或在正在进行的对象分配过程中开始进行垃圾收集是不好的执行一系列优化的CPU指令(请参阅我之前关于编译器的文章),因为您可能会丢失上下文,从而弄乱最终结果。
垃圾收集器永远不要回收主动引用的对象。这样做会破坏。也不需要垃圾收集器立即收集死对象。最终在随后的垃圾回收周期中收集死对象。尽管有很多方法可以实现垃圾回收,但这两个假设对于所有品种都是正确的。垃圾回收的真正挑战是识别所有活动(仍被引用)并回收所有未引用的内存,但这样做不会对运行的应用程序造成不必要的影响。因此,垃圾收集器具有两个任务:
1. 快速释放未引用的内存,以满足应用程序的分配率,以免耗尽内存。
2. 在最小地影响正在运行的应用程序的性能(例如,延迟和吞吐量)的同时回收内存。
两种垃圾收集
在本系列的中,我介绍了垃圾收集的两种主要方法,即引用计数和跟踪收集器。这次,我将进一步深入研究每种方法,然后介绍一些用于在生产环境中实现跟踪收集器的算法。
参考计数收集器
引用计数收集器跟踪指向每个Java对象的引用数量。一旦对象的计数变为零,就可以立即回收内存。立即访问回收的内存是引用计数方法进行垃圾回收的主要优点。保留未引用的内存几乎没有开销。但是,使所有参考计数保持最新可能会非常昂贵。
参考计数收集器的主要困难是保持参考计数准确。另一个众所周知的挑战是与处理圆形结构相关的复杂性。如果两个对象相互引用,并且没有活动对象引用它们,则它们的内存将永远不会释放。这两个对象将永远保持非零计数。回收与圆形结构关联的内存需要进行大量分析,这给算法和应用程序带来了昂贵的开销。
追踪收集者</