《深入理解Java虚拟机》读书笔记(三)- 垃圾回收
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了《深入理解Java虚拟机》读书笔记(三)- 垃圾回收,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4593字,纯文字阅读大概需要7分钟。
内容图文
![《深入理解Java虚拟机》读书笔记(三)- 垃圾回收](/upload/InfoBanner/zyjiaocheng/597/2d1c57572ab244ab9ce6296f1bb55f30.jpg)
1 如何判断对象已经死亡
1.1 引用计数算法
在对象中会有一个引用计数器,每有一个地方引用了这个对象时,计数器的值就+1;引用失效时,计数器的值就-1,当引用计数器的值为0时,表示这个对象就是已经死亡的对象。
引用计数器算法无法解决对象之间相互引用的问题。
1.2 可达性分析算法
这个算法的基本思路就是通过一系列“GC ROOT”的根对象作为起始节点,从这些节点开始根据引用关系向下搜索,搜索过程走过的路径被称为“引用链”,如果某个对象到GC Roots之间没有任何引用链相连,或者说是从GC Roots到这个对象不可达时,则证明这个对象是不可能被使用的,就表示这个对象已经死亡。
那些对象可以被作为GC Roots:
- 在虚拟机栈(栈帧中的本地变量表)中引用的对象,比如在各个线程中内调用的方法堆栈中使用到的参数,局部变量,临时变量等。
- 在方法区中类静态属性引用的对象,比如Java类的引用类型静态变量。
- 在方法区中常量引用的对象,比如字符串常量池中的引用。
- 在本地方法栈中JNI引用的对象
- Java虚拟机内部的引用,如基本数据类型的Class对象,一些常驻的异常对象,系统类加载器等。
- 被锁持有的对象
- 反映Java虚拟机内部情况的JMXBean,JVMTI中注册的回调、本地代码缓存等。
除了这些固定的GC Roots对象之外,根据用户选择的垃圾收集器类型和所收集的区域,还可以有其他对象临时加入到GC Roots 中。
2 引用
Java中的引用是很传统的定义:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称该reference数据代表的是某块内存,某个对象的引用。
在JDK1.2 之后Java对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用强度依次减弱。
2.1 强引用
强引用是传统的“引用”定义,是指在程序代码中普遍存在的引用赋值,即类似于“Object obj = new Object()”这种引用关系。无论任何情况下只要强引用关系还存在,垃圾收集器就不会回收掉对引用的对象。
2.2 软引用
软引用是用来描述一些还有用,但是非必须的对象。只要是被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列入回收范围内进行二次回收。如果这次回收完成后,还没有足够的内存,才会抛出内存溢出异常。在JDK 1.2 之后提供了SoftReference来支持软引用。
2.3 弱引用
弱引用就是用来描述那些非必须对象。被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK1.2之后使用了WeakReference来实现弱引用。
2.4 虚引用
虚引用被称为幽灵引用或者是幻影引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象实例,唯一作用只是为了能在这个对象被垃圾回收器回收时收到一个系统通知。在JDK1.2之后可以使用PhantomReference来实现虚引用。
3 判断对象死亡之后
即使是在根可达性分析中判定位不可达的对象,也不是绝对死亡了,这个时候还处于“缓刑”状态,要真正宣告一个对象死亡,至少要经过两次标记过程,第一次是在根可达性分析中将没有与GC Roots相连接的对象标记出来,第二次是做筛选,判断是否需要执行finalize()方法,如果需要(如果没有覆盖finalize方法,或者是finalize方法已经执行过了,则被视为不需要执行),那么就会将这些对象放入讴歌名为F-Queue的队列中,并在稍后有一条由虚拟机自动建立的,低调度优先级的Finalizer线程去执行他们的finalize()方法,这里的执行是指虚拟机会触发这个方法开始运行,但不保证一定会等待他执行结束。如果在调用完finalize()方法之后,成功的解救了自己,那么就会将这个对象从这个队列中移除,剩下的对象就都是需要被清除的了。
就是相当于虚拟机提供了一种方式可以让你逃脱一次垃圾回收,因为finalize()方法只会执行一次,如果第一次解救成功,再次面临回收时,就不会再执行finalize()方法了。并不鼓励大家使用这种方式来拯救对象,他的运行代价高昂并且不确定性大,无法保证各个对象之间的调用顺序,所以作者建议大家可以忘了这个方法。
4 回收方法区
在方法区进行垃圾收集的性价比要比其他区域的低,在Java堆中,新生代中,对常规应用进行一次回收,通常可以回收很大的内存空间,相比之下,方法区垃圾回收判定条件比较苛刻。
方法区的垃圾主要是两种类型:废弃的常量和不再使用的类型。判断一个常量是否废弃,需要判断这个常量在当前系统中是否有引用,但是判断一个类型是否属于不再被使用的类就比较苛刻了,需要同时满足:
- 该类的所有实例都被回收,当前Java堆中不存在这个类及其任何派生子类的实例。
- 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。
- 该类的Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
如果满足了上面三个要求,那么Java虚拟机被允许进行回收,仅仅是被允许,而不是和对象一样引用没了就必然会被回收。
关于是否要对类型进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class以及-XX:+TraceClass-Loading、-XX:+TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class和-XX:+TraceClassLoading可以在Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版的虚拟机支持。
在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGi这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。
内容总结
以上是互联网集市为您收集整理的《深入理解Java虚拟机》读书笔记(三)- 垃圾回收全部内容,希望文章能够帮你解决《深入理解Java虚拟机》读书笔记(三)- 垃圾回收所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。