JVM GC调优(2)-----GC算法判定对象可以被回收(部分摘自深入理解Java虚拟机)

这次我们介绍JVM中的GC算法

  • 引用计数法
  • 可达性分析法

首先我们提出四个问题

  • 哪里的内存需要回收?
  • 什么时候回收?
  • 如何回收?

Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”, 墙外面的人想进去, 墙里面的人却想出来。

《JVM GC调优(2)-----GC算法判定对象可以被回收(部分摘自深入理解Java虚拟机)》

哪里需要回收?

需要排查各种内存溢出,内存泄漏的问题的时候,当垃圾的收集称为系统高并发量的瓶颈的时候。我们需要堆垃圾收集技术做必要的监控和调节。

  • 由于在线程独占区的线程开始和结束得时候,都会将对应得内存在执行前获取分配好,在方法之完成释放内存。
  • 而在方法执行得过程中在线程共享区,有大量得对象在堆或者方法去创建,这些对象的内存都是动态分配的,所以这里是垃圾收集器所关注的重点。

什么时候回收

当然实在对象死亡的时候做回收,那么在计算机中,我们是如何判断一个对象是否死亡了呢?
1. 引用计数法
这里需要提到的是引用计数法,通过这种方法可以判断对象是否死亡。
《JVM GC调优(2)-----GC算法判定对象可以被回收(部分摘自深入理解Java虚拟机)》

  • 引用计数法的执行原理是:
    给对象中添加一个引用计数器, 每当有一个地方引用它时, 计数器值就加1; 当引用失效时, 计数器值就减1; 任何时刻计数器为0的对象就是不可能再被使用的。
  • 缺点做详细说明
    按照上面的执行原理,如果我们创建两个对象相互引用,实际他们已经可以判定i死亡了,但是通过引用计数法是没有办法完成判定的,而在我们的Java语言中,面向对象是一个很常见的过程,所以JVM中一般不采用这种算法。
	Object obj01 = new Object();
        Object obj02 = new Object();
 	//相互引用
        obj01=obj02;

2. 可达性分析法

可达性分析法的直白意思就是:是否可以到达的分析法。在主流程序语言都是用这种方法(Java、 C#, 甚至包括前面提到的古老的Lisp)
《JVM GC调优(2)-----GC算法判定对象可以被回收(部分摘自深入理解Java虚拟机)》

  • 工作原理:
    首先设定一个根节点,GCRoot, 从这些节点开始向下搜索, 搜索所走过的路径称为引用链( Reference Chain) , 当一个对象到GC Roots没有任何引用链相连时候则证明此对象不可用,如上图,object5,object6,object7,没有于根节点连接,所以判断位可回收对象。
  • 常见的GCRoot节点对象
    在Java语言中, 可作为GC Roots的对象包括下面几种:
    • 虚拟机栈( 栈帧中的本地变量表) 中引用的对象。
    • 方法区中类静态属性引用的对象。
    • 方法区中常量引用的对象。
    • 本地方法栈中JNI( 即一般说的Native方法) 引用的对象。

PS: 这里我们增加对于方法区的垃圾回收介绍
一般情况,垃圾回收会集中在堆内存的Eden区域进行,这里会回收释放70%~ 95%的空间。而方法区的回收效率低成本高。

  • 永久代的垃圾收集主要回收两部分内容:
    废弃常量和无用的类
    废弃常量的回收和Java堆中的对象回收类似,以常量池中字面量的回收为例, 假如一个字符串“abc”已经进入了常量池中, 但是当前系统没有任何一个String对象是叫做“abc”的, 换句话说, 就是没有任何String对象引用常量池中的“abc”常量, 也没有其他地方引用了这个字面量, 如果这时发生内存回收, 而且必要的话, 这个“abc”常量就会被系统清理出常量池。 常量池中的其他类( 接口) 、 方法、 字段的符号引用也与此类似。

  • 判断无用的类需要满足一下三个条件:

    • 该类所有的实例都已经被回收, 也就是Java堆中不存在该类的任何实例。
    • 加载该类的ClassLoader已经被回收。
    • 该类对应的java.lang.Class对象没有在任何地方被引用, 无法在任何地方通过反射访问该类的方法。
    原文作者:java虚拟机
    原文地址: https://blog.csdn.net/weixin_42229056/article/details/82932110
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞