JVM笔记 | Java垃圾回收(GC)

简介: 概述在JVM的运行时数据区中,程序计数器、JVM栈和本地方法栈随线程而生,随线程而灭,内存分配和回收具备确定性,因此这几个区域不需要过多考虑内存回收问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。
概述

在JVM的运行时数据区中,程序计数器、JVM栈和本地方法栈随线程而生,随线程而灭,内存分配和回收具备确定性,因此这几个区域不需要过多考虑内存回收问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,只有在程序处于运行期才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关心的是这部分内存。

对象存活判定算法

在堆中存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象中哪些还“存活”着,那些已经“死去”(即不可能再被任何途径使用的对象)

1. 引用的概念

在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用和虚引用四种,这四种引用强度依次减弱。

  • 强引用(Strong Reference)
    • 指创建一个对象并把这个对象赋值给一个引用变量
      Object obj = new Object();
    • 只要强引用存在,即使抛出OutOfMemoryError异常,垃圾收集器也不会回收被引用的对象。
  • 软引用(Soft Referrence)
    • 用来描述一些还有用但非必须的对象。
    • 对于软引用关联的对象,在内存不足时会被回收。
  • 弱引用(Weak Reference)
    • 用来描述非必须对象,但强度比软引用更弱。
    • 无论当前内存是否足够,都会被回收。
  • 虚引用(Phantom Reference)
    • 不影响对象生存时间,也无法通过虚引用取得对象实例。
    • 存在意义在于与引用队列关联使用,判断被虚引用关联的对象是否即将被回收。

推荐阅读:Java的四种引用方式

2. 引用计数算法

  • 实现方式:给对象中添加一个引用计数器,每当有一个地方去引用它,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器值为0的对象就是不可能再被使用的。
  • 这种算法实现简单、判定效率高,但是很难解决对象之间相互循环引用的问题。
  • 虚拟机不是通过引用计数算法来判断对象是否存活。

3. 可达性分析算法

  • 实现方式:通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,证明此对象是不可引用的。
    img_db6f25eaac2240999491ab0c27d8a730.png
  • 在Java中,可作为GC Roots的对象包括以下几种:
    • JVM栈(栈帧中的本地变量表)中引用的对象;
    • 方法区中类的静态属性引用的对象;
    • 方法区中常量引用的对象;
    • 本地方法栈中JNI(即常说的Native方法)引用的对象。
  • 当然,可达性分析算法中不可达的对象并不是一定会被回收,如果这个对象在执行finalize()方法时,重新与引用链上的对象关联起来,就会被移除出“即将回收”集合。

4. 方法区回收

  • JVM规范中说过可以不要求JVM在方法区实现垃圾回收,方法区的垃圾回收效率十分低。
  • 方法区的垃圾回收主要回收两部分内容:
    • 废弃常量的回收与Java堆中对象的回收十分类似,即没有被任何其他地方引用就会被回收。
    • 满足以下条件会被判定为无用的类
      • 该类所有的实例都已经被回收,即Java堆中不存在该类的任何实例;
      • 加载该类的 ClassLoader 已经被回收;
      • 该类对应的 java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
垃圾收集算法

首先可以先看看下面这篇博客,了解一下新生代和老年代的概念:新生代和老年代
接下来介绍几种垃圾收集算法。

1. 复制算法

  • 算法思想:将可用内存按容量划分为大小相等的两块,每次只使用其中给一块,当这一块的内存用完了,就将还存活的对象复制到另一块,再将已使用的一块内存全部清理掉。
  • 优点:每次都对整个半区进行回收,不会产生内存碎片,实现简单,运行高效。
  • 缺点:相当于将可用内存缩小为一半,使用率太低。
    img_aaf8cca169da4bb82f942406288ecfa4.png

2. 标记—清除算法

  • 算法思想:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
  • 不足:
    • 标记和清除两个过程的效率都不高;
    • 标记清除后会产生大量不连续的内存碎片,造成后面无法为较大对象分配空间,频繁触发垃圾收集,影响系统性能。
      img_8bdf82f2c08dd6cc364f63ae726b641d.png

3. 标记—整理算法

  • 算法思想:首先标记出所有需要回收的对象,然后将所有存活的对象移动到一端,然后直接清理端边界以外的全部内存。
  • 优点:可以应对大量对象存活,只有少量内存需要回收的情况,适合老年代使用。
    img_101d2f9b83da652361d5838e379ab0a4.png

4. 分代收集算法

  • 这种算法被当代虚拟机广泛使用。
  • 算法思想:根据对象存活周期将Java堆分为新生代和老年代,分别使用合适的算法进行垃圾收集。
    • 新生代对象存活率低,使用复制算法,只需付出少量存活对象的复制成本就可以完成收集。

    IBM公司的专门研究表明,新生代中的对象98%是“朝生夕死”,所以可以将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor空间。回收时,将这两块空间中存活的对象复制到另一块Survivor空间中,最后清理掉Eden和Survivor空间。这样空间使用率就达到了90%。当然我们不能保证每次都只有不多于10%的对象存活,这时就需要依赖老年代空间进行分配担保,即让survivor空间存放不下的对象通过分配担保机制进入老年代。

    • 老年代对象存活率高,使用标记—清理算法或者标记—整理算法。

上一篇:JVM笔记 | Java内存管理

相关文章
|
5月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
529 55
|
6月前
|
监控 Java Unix
6个Java 工具,轻松分析定位 JVM 问题 !
本文介绍了如何使用 JDK 自带工具查看和分析 JVM 的运行情况。通过编写一段测试代码(启动 10 个死循环线程,分配大量内存),结合常用工具如 `jps`、`jinfo`、`jstat`、`jstack`、`jvisualvm` 和 `jcmd` 等,详细展示了 JVM 参数配置、内存使用、线程状态及 GC 情况的监控方法。同时指出了一些常见问题,例如参数设置错误导致的内存异常,并通过实例说明了如何排查和解决。最后附上了官方文档链接,方便进一步学习。
799 4
|
2月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
238 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
3月前
|
存储 运维 Kubernetes
Java启动参数JVM_OPTS="-Xms512m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError"
本文介绍了Java虚拟机(JVM)常用启动参数配置,包括设置初始堆内存(-Xms512m)、最大堆内存(-Xmx1024m)及内存溢出时生成堆转储文件(-XX:+HeapDumpOnOutOfMemoryError),用于性能调优与故障排查。
366 0
|
5月前
|
存储 监控 算法
Java程序员必学:JVM架构完全解读
Java 虚拟机(JVM)是 Java 编程的核心,深入理解其架构对开发者意义重大。本文详细解读 JVM 架构,涵盖类加载器子系统、运行时数据区等核心组件,剖析类加载机制,包括加载阶段、双亲委派模型等内容。阐述内存管理原理,介绍垃圾回收算法与常见回收器,并结合案例讲解调优策略。还分享 JVM 性能瓶颈识别与调优方法,分析 Java 语言特性对性能的影响,给出数据结构选择、I/O 操作及并发同步处理的优化技巧,同时探讨 JVM 安全模型与错误处理机制,助力开发者提升编程能力与程序性能。
Java程序员必学:JVM架构完全解读
|
5月前
|
缓存 算法 Java
JVM深入原理(八)(一):垃圾回收
弱引用-作用:JVM中使用WeakReference对象来实现软引用,一般在ThreadLocal中,当进行垃圾回收时,被弱引用对象引用的对象就直接被回收.软引用-作用:JVM中使用SoftReference对象来实现软引用,一般在缓存中使用,当程序内存不足时,被引用的对象就会被回收.强引用-作用:可达性算法描述的根对象引用普通对象的引用,指的就是强引用,只要有这层关系存在,被引用的对象就会不被垃圾回收。引用计数法-缺点:如果两个对象循环引用,而又没有其他的对象来引用它们,这样就造成垃圾堆积。
162 0
|
5月前
|
算法 Java 对象存储
JVM深入原理(八)(二):垃圾回收
Java垃圾回收过程会通过单独的GC线程来完成,但是不管使用哪一种GC算法,都会有部分阶段需要停止所有的用户线程。这个过程被称之为StopTheWorld简称STW,如果STW时间过长则会影响用户的使用。一般来说,堆内存越大,最大STW就越长,想减少最大STW,就会减少吞吐量,不同的GC算法适用于不同的场景。分代回收算法将整个堆中的区域划分为新生代和老年代。--超过新生代大小的大对象会直接晋升到老年代。
117 0
|
7月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
9月前
|
存储 Java 开发者
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。
本文详细介绍了 Java 中 `toString()` 方法的重写技巧及其重要
464 10
【潜意识Java】深入详细理解分析Java中的toString()方法重写完整笔记总结,超级详细。