Java中的每个对象都经历了创建、使用和最终被回收的过程。从对象实例化开始,它可能被程序的多个部分引用,直到最后一个引用消失,对象成为垃圾,等待回收。
(1)引用计数法:已淘汰,为每个对象添加引用计数器,引用为0时判定可以回收,会有两个对象相互引用无法回收的问题
(2)可达性分析法:从GCRoot开始往下搜索,搜索过的路径称为引用链,若一个对象GCRoot没有任何的引用链,则判定可以回收(三色法:未标记、标记中、已标记)
可以作为GC Roots的主要有四种对象:
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI引用的对象
(1)标记清除算法: 标记不需要回收的对象,然后清除没有标记的对象,会造成许多内存碎片。
(2)复制算法: 将内存分为两块,只使用一块,进行垃圾回收时,先将存活的对象复制到另一块区域,然后清空之前的区域。用在新生代
优点:解决碎片化问题,顺序分配内存简单高效
缺点:只适用于存活率低的场景,如果极端情况下如果对象面上的对象全部存活,就要浪费一半的存储空间。
(3)标记整理算法: 与标记清除算法类似,但是在标记之后,将存活对象向一端移动,然后清除边界外的垃圾对象。用在老年代
(4)分代收集算法:一般将 java 堆分为新生代和老年代,比如在新生代中,选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,选择“标记-清除”或“标记-整理”算法进行垃圾收集。
Edan
区、Survivor区(from/S1
区、to/S2
区),这三者的区域大小划分比例为8:1:1
15
次之后会被移到老年代(这个值可以通过JVM参数:–XX:SurvivorRatio 设定,默认值为8)1:2
(该值可以通过JVM参数:-XX:NewRatio 设定)当GC确定一些对象为“不可达”时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
## 第一步:
大对象直接进入老年代
长期存活对象将进入老年代
1. Eden 区
Java 新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当 Eden 区内存不够的时候就会触发 MinorGC,对新生代区进行一次垃圾回收。
2. ServivorFrom
上一次 GC 的幸存者,作为这一次 GC 的被扫描者。
3. ServivorTo
保留了一次 MinorGC 过程中的幸存者。
## 第二步:
老年代的对象比较稳定,所以 MajorGC 不会频繁执行。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次 MajorGC 进行垃圾回收腾出空间。
MajorGC 采用标记清除算法:
首先扫描一次所有老年代,标记出存活的对象,然后回收没有标记的对象。MajorGC的耗时比较长,因为要扫描再回收。MajorGC 会产生内存碎片,为了减少内存损耗,我们一般需要进行合并或者标记出来方便下次直接分配。
## 第三步:
当老年代也满了装不下的时候,就会抛出 OOM(Out of Memory)异常.
永久代:主要存放 Class 和 Meta(元数据)的信息,Class 在被加载的时候被放入永久区域,它和和存放实例的区域不同,GC 不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的 Class 的增多而胀满,最终抛出 OOM 异常。
在 Java 中,Reference
类及其子类是用于实现引用对象的基类。Reference
类主要有三个子类:SoftReference
、WeakReference
、和 PhantomReference
,它们分别代表软引用、弱引用和虚引用。
可达状态
,它是不可能被垃圾回收机制回收的,因此强引用是造成 Java 内存泄漏的主要原因之一。垃圾回收(GC)时,即使内存空间足够,也会被回收
作用是跟踪对象被垃圾回收的状态以及引用对象被放入与之关联的引用队列中,允许程序员在适当的时机进行一些额外的操作
。垃圾回收器(garbage colector)决定回收某对象时,就会运行该对象的finalize()方法:
## 如何选择:
**响应时间要求**:如果应用对延迟非常敏感,那么选择如ZGC或CMS这样的暂停时间短的垃圾回收器会更合适。
**吞吐量要求**:高吞吐量的应用,如批处理作业或某些后端任务,可能更适合使用Parallel GC或G1 GC。
**内存资源**:如果内存资源有限,Serial GC可能是一个好选择。
GC日志: JVM可以配置为输出GC日志,这些日志详细记录了垃圾回收的过程和结果。通过分析这些日志,开发者可以获取关于内存使用情况、垃圾收集的频率和持续时间等重要信息。
监控工具: 工具如JVisualVM和JConsole不仅可以实时显示JVM的性能指标,还提供了丰富的图形界面,帮助开发者直观地了解垃圾回收的行为。