1.概述
最近通过看书系统的了解了JVM的GC原理,发现之前自己很多地方理解有偏差,不够详细。之前写过一篇JVM垃圾回收机制的文章,写的太乱了不想再后面加了,所以重开一篇。这篇文章主要介绍基本概念和JVM的对象存活判定。
1.1 什么是垃圾回收
JVM会自动给我们分配内存和释放内存,简单来说,jvm释放内存的过程就是垃圾回收。这里需要注意的是:JVM回收的是“垃圾”对象所占用的内存。
1.2 为什么要进行垃圾回收
- 避免内存溢出、内存泄漏
- 合理利用内存,防止垃圾对象占用内存
1.3 学习垃圾回收机制的意义
当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。
2.对象存活判定
2.1 判定方法
2.1.1 引用计数法
原理
给对象添加一个引用计数器,当有一个地方引用该对象时,计数器值加一;当引用失效时,计数器值就减一。当计数器为零时,表示该对象没有在任何地方被引用,则该对象可以判定为可回收对象。
缺陷
无法解决循环引用的问题。当两个对象互相引用时,则永远不会被回收。
2.1.2 可达性算法
在主流语言的主流实现中,都是通过可达性算法来判定对象是否存活。
原理
以被称为“GC Roots”的对象为起点,从这些节点向下搜索,搜索的路径被称为引用链。当对象没有任何的引用链与“GC ROOTS”相连,则该对象则被判定为可回收对象。
如图,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。
GC Roots
在java语言中,可作为GC Roots的对象包括下面几种:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(即一般说的Native方法)引用的对象
3.对象引用
从上面的判定算法可以看出,我们看重的是对象引用。实际上在JVM中,对象引用不仅仅是有或无两种形式。无论是哪种判定对象存活的方法,根本是在判定“引用”是否存在。java有四种引用:强引用、软引用、弱引用和虚引用。
名称 | 定义 | 回收情况 |
---|---|---|
强引用 | 一般使用的引用,比如new出来的对象,即“Object object = new Object()” | 在对象没有被根引用链接的时候被回收 |
软引用 | 有用但非必须的对象,比如一些缓存对象 | 在系统将要发生内存溢出前,才会将这些引用列入回收范围,进行一次回收操作。在这次回收之后,系统仍然还没有足够的内存,才会抛出内存溢出异常 |
弱引用 | 用来描述非必须对象,强度低于软引用 | 只存活到下一次垃圾回收之前,当垃圾回收开始,无论内存是否足够,都会回收 |
虚引用 | 为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一条系统通知。 | 一个对象有无虚引用,不影响他生存时间;通过一个虚引用也无法获取一个对象实例 |
4.对象被回收过程
对象通过finalize()方法逃脱GC的过程.pngfinalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的
需要注意的是,任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行,即对象只能自救一次。
5.方法区回收
这里说的方法区,在hotspot中叫做“永久代”,java虚拟机规范中不要求一定要实现方法区的垃圾回收。原因主要是由于方法区回收的性价比太低。
5.1 方法区垃圾主要内容
5.1.1 废弃常量
以常量池中字面量的回收为例,假如一个字符串"abc"已经进入了常量池中,没有任何String对象引用常量池中的"abc"常量,也没有其他地方引用了这个字面量,这个"abc"常量就会被系统清理出常量池
5.1.2 无用的类
同时满足下面三个条件可以回收:
- 该类所有的实例都已经被回收,即Java堆中不存在该类的任何实例
- 加载该类的ClassLoader已经被回收
- 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法
需要注意的是,这里说的是“可以回收”,而不是一定回收。类的回收和对象的回收不一样的地方就在此。是否对类进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制。
还可以使用-verbose:class以及-XX:+TraceClassLoading、
-XX:+TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class和-XX:+TraceClassLoading可以在Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版的虚拟机支持。
网友评论