JVM垃圾回收算法的概念与分析

 更新时间:2019年12月17日 08:30:57   作者:架构文摘  
这篇文章主要给大家介绍了关于JVM垃圾回收算法的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用JVM具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

在JVM内存模型中会将堆内存划分新生代、老年代两个区域,两块区域的主要区别在于新生代存放存活时间较短的对象,老年代存放存活时间较久的对象,除了存活时间不同外,还有垃圾回收策略的不同,在JVM中中有以下回收算法:

  • 标记清除
  • 标记整理
  • 复制算法
  • 分代收集算法

有了垃圾回收算法,那JVM是如果确定对象是垃圾对象的呢?判断对象是否存活JVM也会有几套自己判断算法了:

  • 引用记数
  • 可达性分析

有了垃圾回收和判断对象存在这两个概念后,再来逐步分析它们。

JVM是如何判断对象是否存活的?

要是让开发人员来判断一个对象是否有用是很简单的,简单的说就是:对象没有任何引用就认为该对象可以被回收了。假设有如下程序代码:

public class App {

 public static void main(){
  checkFile("/");
 }

 public static boolean checkFile(String path ){
  File file = new File(path);
  return file.exists();
 }
}

程序执行起来在调用checkFile的时候JVM图大概像这样:

到checkFile方法执行完成之后,它里面的局部变量file就会随着栈帧一起被清理,这个时候还存活在JVM堆中的File对象也是无用的了:

要是人为来判断非常清晰的就发现File对象已经无用了,那换成JVM它又是如何来判断对象是否能存活的呢?

引用记数

引用记数算法原理比较简单,想象下有个对象它有一个count属性,每次引用该对象都会使count加1,假设JVM在判断该对象是否存活的时候去检查这个count属性,发现这个属性不为0说明还有其他对象在引用该对象。

等到checkFile方法执行完之后count就会减1变成0:

这样一来JVM就很容易判断一个对象是否存活了。

但是引用记数有一个明显的缺点,就是无法解决循环引用的问题比如:A --> B --> A 这样的对象关系它是没有办法来判断对象是否该不该回收的。

GC Root(可达性分析)

为什么会被称为可达性分析算法呢?可以这样理解如果通过GC Root能到达一个对象那么这个对象就是存活的。那什么样的对象才是GC Root呢?

在Java语言中,可作为GC Roots的对象包括下面几种:

  1. 虚拟机栈中引用的对象(栈帧中的本地变量表);
  2. 方法区中类静态属性引用的对象;
  3. 方法区中常量引用的对象;
  4. 本地方法栈中JNI(Native方法)引用的对象。

还是用上面的例子,在checkFile方法执行时,因为栈帧变量file可做为GC Root所以在执行期间JVM是绝对不会回收掉这个File对象:

但是等到checkFile执行完成之后,这个栈帧会被弹出,其中的变量也会被释放,相应的没有GC Root能到达堆中的File对象,这个时候就可以判断这个对象是一个无用的对象了,然后安全回收。

垃圾收回算法

标记清除

这种算法分两分:标记、清除两个阶段,

标记阶段是从根集合(GC Root)开始扫描,每到达一个对象就会标记该对象为存活状态,清除阶段在扫描完成之后将没有标记的对象给清除掉。

用一张图说明:

这个算法有个缺陷就是会产生内存碎片,如上图B被清除掉后会留下一块内存区域,如果后面需要分配大的对象就会导致没有连续的内存可供使用。

标记整理

标记整理就没有内存碎片的问题了,也是从根集合(GC Root)开始扫描进行标记然后清除无用的对象,清除完成后它会整理内存。

这样内存就是连续的了,但是产生的另外一个问题是:每次都得移动对象,因此成本很高。

复制算法

复制算法会将JVM推分成二等分,如果堆设置的是1g,那使用复制算法的时候堆就会有被划分为两块区域各512m。给对象分配内存的时候总是使用其中的一块来分配,分配满了以后,GC就会进行标记,然后将存活的对象移动到另外一块空白的区域,然后清除掉所有没有存活的对象,这样重复的处理,始终就会有一块空白的区域没有被合理的利用到。

两块区域交替使用,最大问题就是会导致空间的浪费,现在堆内存的使用率只有50%。

分代回收

新生代回收

JVM的堆分为新生代和老年代,两种类型有不同的特性,根据它们的特性来选择不同的回收算法,这种算法会将新生代划分为一块Eden和二个Survivor区:

如上面的图有三块区域它们会按照8:1:1的比例进行分配,如1000m的堆Eden是800m,二个Survivor各占100m,那它们是如何运行的呢?

  1. 始终会有一块Survivor是空着的,内存使用率是90%
  2. 程序运行会在Eden和其中一块Survivor 1中分配内存
  3. 等到执行Minor gc,会将存活下来的对象移动到空着的Survivor 2中
  4. 然后在Eden和Survivor 2中继续分配内存,Survivor 1空着等着下次使用

这样就能使内存使用率达到90%,也不会产生内存碎片。

老年代回收

老年代对象即使进行了垃圾回收,对象的存活率也高,所以采用标记清除或标记整理算法都是不错的选择,这里就不做阐述。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。

相关文章

  • springboot项目数据库配置类DatabaseConfig示例详解

    springboot项目数据库配置类DatabaseConfig示例详解

    这篇文章主要介绍了springboot项目数据库配置类DatabaseConfig实现代码,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 带你3分钟带你搞定Spring Boot中Schedule

    带你3分钟带你搞定Spring Boot中Schedule

    本文主要围绕Spring scheduled应用实践进行分享,如果是单体应用,使用SpringBoot内置的@scheduled注解可以解决大部分业务需求,对Spring Boot中Schedule 相关知识感兴趣的朋友一起看看吧
    2024-07-07
  • Spring常用注解及自定义Filter的实现

    Spring常用注解及自定义Filter的实现

    这篇文章主要介绍了Spring常用注解及自定义Filter的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • java定位死锁的三种方法(jstack、Arthas和Jvisualvm)

    java定位死锁的三种方法(jstack、Arthas和Jvisualvm)

    这篇文章主要给大家介绍了关于java定位死锁的三种方法,分别是通过jstack定位死锁信息、通过Arthas工具定位死锁以及通过 Jvisualvm 定位死锁,文中还介绍了死锁的预防方法,需要的朋友可以参考下
    2021-09-09
  • Java容器ArrayList知识点总结

    Java容器ArrayList知识点总结

    本篇文章给大家分享了Java容器ArrayList的相关知识点,对此有需要的朋友可以跟着学习参考下。
    2018-05-05
  • Java单例模式的深入了解

    Java单例模式的深入了解

    这篇文章主要为大家介绍了Java单例模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • java类Circle定义计算圆的面积和周长代码示例

    java类Circle定义计算圆的面积和周长代码示例

    要用Java计算圆的周长和面积,需要使用圆的半径和一些数学公式,下面这篇文章主要给大家介绍了关于java类Circle定义计算圆的面积、周长的相关资料,需要的朋友可以参考下
    2024-04-04
  • 解决@SpringBootTest 单元测试遇到的坑

    解决@SpringBootTest 单元测试遇到的坑

    这篇文章主要介绍了解决@SpringBootTest 单元测试遇到的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 解决程序启动报错org.springframework.context.ApplicationContextException: Unable to start web server问题

    解决程序启动报错org.springframework.context.ApplicationContextExcept

    文章描述了一个Spring Boot项目在不同环境下启动时出现差异的问题,通过分析报错信息,发现是由于导入`spring-boot-starter-tomcat`依赖时定义的scope导致的配置问题,调整依赖导入配置后,解决了启动错误
    2024-11-11
  • 详解Spring Cloud Eureka多网卡配置总结

    详解Spring Cloud Eureka多网卡配置总结

    本篇文章主要介绍了详解Spring Cloud Eureka多网卡配置总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04

最新评论