什么是Java垃圾回收机制
Java中的垃圾回收机制是自动管理内存的一个过程,通过回收不再被应用程序引用的对象来释放内存空间,它的重要性在于减少了程序员手动管理内存的负担,降低了内存泄漏和其他内存错误的风险。
Java垃圾回收的工作原理是什么?
Java垃圾回收通过追踪和管理对象来确定哪些对象不再被使用。当对象不再被引用时,垃圾回收器可以自动回收这些对象占用的内存空间主要的垃圾回收算法有标记-清楚,复制算法,标记-压缩等。
可达性分析法(Java垃圾回收通过追踪和管理对象的方法)
这个算法的级别思想是通过一系列称为“GC Roots”的对象作为起点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的。
选取GC Roots对象
GCRoots包括:
1.虚拟机栈(栈帧中的局部变量,也叫局部变量表)中引用的对象。
2.方法区中的类静态属性引用的对象。
3.方法区中常量引用的对象。
4.本地方法栈中JNI(Native方法)引用的对象
引用状态(明确删除对象的优先级)
1.强引用
代码中普遍存在类似“Object obj = new Object()”这类的引用,只要强引用还在,垃圾收集器永远不会回收掉引用的对象。
2.软引用
描述还有用但并非必需的对象。在系统将要发生内存溢出异常前,将会把这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。Java中类SoftReference表示软引用。
3.弱引用
描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。Java中的类WeakReference表示弱引用。
4.虚引用
这个引用存在的唯一目的就是在这个对象被回收器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。Java中的类PhantomReference表示虚引用。
垃圾回收过程
在JVM开始运行的时候,所有区域都处于空闲状态。一个对象刚刚被new关键字创建出来的时候,会在伊甸区中选择一个空闲的区域来进行存放。
当创建的对象过多,伊甸区达到饱和,这时候就会出发Minor GC,进行垃圾回收,GC会挑出一些空闲空间作为幸存区,如此反复,幸存区的对象每经历一次GC,年龄就会+1,当达到15这个默认值的时候对象会被移动到老年区。
直到老年区也达到饱和,无法存放新创建的对象。JVM会进行FullGC,若这样还无法保存对象,会产生OOM。知道内存达到上限的时候,才会开始清理。
垃圾回收算法
1,复制算法
Java垃圾回收中的复制算法(Copying Algorithm)是一种内存管理技术,主要用于年轻代(Young Generation)中的垃圾回收。其核心思想是将堆内存分为两个等大的空间:From Space 和 To Space。当垃圾回收开始时,所有存活的对象从 From Space 复制到 To Space,然后清空 From Space。
具体步骤如下:
- 对象分配:对象最初分配在 From Space。
- 垃圾回收开始:当 From Space 被填满时,垃圾回收器会启动。
- 存活对象复制:遍历 From Space 中的对象,将仍然存活的对象复制到 To Space。
- 交换空间:复制完成后,交换 From Space 和 To Space 的角色,To Space 变成新的 From Space,而旧的 From Space 则被清空,成为新的 To Space。
- 继续分配:新对象继续在新的 From Space 中分配。
这种方法的优点是避免了内存碎片化,且回收过程简单高效,但由于需要预留相同大小的内存空间,因此内存利用率较低。
2,标记-整理
Java垃圾回收中的标记-整理算法(Mark-Compact)是一种用于老年代(Old Generation)内存管理的技术,旨在提高内存利用率并减少碎片化问题。
该算法的工作过程分为两个主要阶段:
-
标记阶段(Marking Phase):垃圾回收器首先遍历所有对象,从根对象(如栈、静态变量等)开始,标记所有存活的对象。这一过程类似于标记-清除(Mark-Sweep)算法中的标记阶段。
-
整理阶段(Compaction Phase):在标记完成后,垃圾回收器将所有存活的对象压缩到堆的另一端,使它们紧密排列,消除内存中的碎片。然后,更新所有相关的引用,以指向新位置。
优点:
- 消除了内存碎片问题,因为存活对象被压缩到一起,剩下的内存空间是连续的。
- 更适合老年代内存管理,因为老年代中对象存活率较高。
缺点:
- 整理阶段的操作较为复杂,需要移动对象和更新引用,因此开销较大。
3,标记-清除
Java垃圾回收中的标记-清除算法(Mark-Sweep)是一种经典的垃圾回收算法,用于老年代(Old Generation)内存管理。它分为两个主要阶段:
-
标记阶段(Marking Phase):垃圾回收器从根对象(如栈中的变量、静态变量等)开始遍历,标记所有存活的对象。任何无法从根对象访问的对象都被视为垃圾。
-
清除阶段(Sweeping Phase):在标记完成后,垃圾回收器遍历堆中的所有对象,清除未被标记的对象,释放它们占用的内存。
优点:
- 实现简单,适用于各种类型的内存分配。
缺点:
- 它会导致内存碎片化,因为清除后空闲内存块分布不连续。
- 内存碎片化会影响性能,可能导致以后分配大对象时需要进行内存整理。
4,分代收集
Java垃圾回收中的分代收集(Generational Garbage Collection)是一种优化内存管理的技术,它根据对象的生命周期将堆内存分为不同的代,以提高垃圾回收的效率。
主要分为以下几代:
-
年轻代(Young Generation):
- 包含所有新创建的对象。
- 大多数对象在这里很快变为垃圾,因此年轻代使用频繁的垃圾回收(称为“Minor GC”),通常采用复制算法。
- 年轻代又分为三个区域:Eden Space、From Space 和 To Space。
-
老年代(Old Generation):
- 包含生命周期较长的对象,即在年轻代中经历多次垃圾回收后仍然存活的对象会被晋升到老年代。
- 老年代的垃圾回收(称为“Major GC”或“Full GC”)较少发生,但回收过程更耗时,通常采用标记-清除或标记-整理算法。
-
永久代(Permanent Generation):
- 存储Java类元数据、方法等永久性信息。
- 在Java 8及以后,永久代被替换为元空间(Metaspace),由本地内存管理。
优点:
- 分代收集利用了大多数对象“朝生夕死”的特点,频繁回收年轻代中的短命对象,大大提高了垃圾回收的效率。
- 将生命周期不同的对象分开管理,减少了不必要的扫描和处理。
这种分代机制使得垃圾回收器能更高效地处理内存,优化了程序的运行性能。
垃圾回收器
Java中的垃圾回收器是负责自动管理内存的组件,它会识别和回收不再使用的对象,以释放内存空间。Java提供了多种垃圾回收器,每种都有不同的特点和适用场景。
主要垃圾回收器:
-
Serial GC:
- 单线程工作,适用于单核处理器或内存较小的场景。
- 简单高效,但在垃圾回收期间会暂停所有应用线程(Stop-The-World)。
-
Parallel GC(也称为“Throughput GC”):
- 多线程工作,适用于多核处理器。
- 重点在于提高吞吐量,适合后台任务或批处理应用。
-
CMS GC(Concurrent Mark-Sweep):
- 主要用于老年代的并发标记-清除垃圾回收器。
- 减少了停顿时间,但可能导致内存碎片化。
-
G1 GC(Garbage First):
- 分代收集与区域化收集结合,适合大堆内存应用。
- 通过预测性模型控制停顿时间,减少长时间的停顿。
-
ZGC(Z Garbage Collector):
- 超低停顿时间的垃圾回收器,适合需要极低延迟的应用。
- 处理大堆内存,通常在几毫秒内完成垃圾回收。
-
Shenandoah GC:
- 类似ZGC的低停顿垃圾回收器。
- 在并发的标记和压缩阶段进一步减少停顿时间。
选择垃圾回收器:
- 选择适当的垃圾回收器取决于应用程序的需求,例如需要高吞吐量、低停顿时间,还是适用于大内存场景。开发者可以通过JVM参数(如
-XX:+UseG1GC
)来指定使用哪种垃圾回收器。