Java虚拟机系列003

JVM垃圾收集

垃圾收集器的历史比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。

对于垃圾回收,我们首先考虑的是什么样的对象为可回收对象,即使对象什么时候判定为死亡,其次是什么时候进行回收,最后是如何回收。

1.什么样的对象为可回收对象?

当对象死亡,JVM便对其分配的内存进行回收,对其进行销毁。

⑴如何判断对象死亡,即什么才算对象死亡?

引用计数算法

给对象添加一个引用计数器,当对象被引用的时候,计数器就加一,当引用失效的时候,计数器的值就减一,当计数器的值为0时,这个对象便不在被使用便可以被GC进行回收。

引用计数算法,简单,高效,判定效率也很高,也是一个不错的算法,但至少主流的Java虚拟机没有选用引用计数法来管理内存,其主要的原因是它很难解决对象之间相互循环引用问题,ex:objA.instance = objb及objB.instance =objA,这两个对象已再无其他引用,实际上这两个对象已经不可能在被访问,但是因为他们互相引用着对方,导致引用计数器的计数值不为0,所以GC收集器无法回收们。

可达性分析算法

在主流的程序语言的主流实现中,都是称通过可达性分析算法来判断对象是否存活。可达性分析算法,就是通过一个称为“GC Roots”的对象作为起始点,从这些节点开始往下搜索,搜索所走过的路径称为引用链,当一个对象到达GC Roots没有任何引用链相连的时候,也就是GC Roots到这个对象不可达,则证明此对象不可用。

可作为GC  Roots对象包括:虚拟机栈中引用的对象,方法区中类的静态属性引用的对象,方法区中常量引用的对象,Native引用过的对象。

引用的分类

在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用,软引用,弱引用,虚引用

强引用:也就是使用new关键字创建的对象,只要引用还在,垃圾收集器就永远不会回收掉被引用的对象。

软引用:引用一些非必需的对象,对于软引用的对象,当系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行二次回收。如果回收后还没有足够的内存,才会抛出异常。JDK1.2之后,提供SoftReference类来实现软引用。 

弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会回收掉被弱引用关联的对象。在JDK1.2之后,提供WeakReference类来实现弱引用。

虚引用:最弱的一种,一个对象是否有虚引用的存在,完全不会对其生存期间构成影响,也无法通过虚引用来取得一个对象实例。在JDK1.2之后,提供了PhantomReference类来实现。

2.什么时候进行回收?

当对象的引用计数为0或者在可达性分析算法中不可达时,就进行回收。

即使在可达性分析算法中不可达的对象,也并非非死不可,要真正宣告一个对象的死亡,需要经历两次标记过程。

当对象在进行可达性分析算法中,没有与GC Roots相连接,则会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者虚拟机没有调用过此方法,虚拟机都将视为“没有必要执行”。如果对象被判定为有必要执行,他将会被放置到一个F-Queue队列中,队列是一个先进先出的数据结构。Finalize()方法是对象逃脱死亡的最后一个机会,所以要想拯救,只需重新与引用链上的任何一个对象建立关联即可。

3.如何回收?垃圾收集算法有哪些

⑴标记-清除算法

首先标记出所有需要回收的对象,标记结束后再进行统一的回收。缺点:产生大量的内存碎片,效率不是太高

⑵复制算法

将内存划分为大小相等的两部分,每次只使用其中的一个,当这一块用完了,就将还存活的对象复制到另外一块上面,然后把已使用过那块的内存空间一次清理掉。优点:简单,高效。

⑶标记-整理算法

与标记-清除算法一样,但后续步骤不是直接进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

⑷分代收集算法

根据对象的存活周期的不同将内存划分为几块。一般把Java堆划分为新生代和老年代,根据不同的各个年代的特点采用最适当的收集算法。在新生代中,一般采用复制算法,因为新生代对象活动频繁,生死操作快。而在老年代因为对象存活率高,所以就必须使用标记-清理或者标记-整理来进行回收。

4.回收方法区

很多人认为方法区(在HopSpot虚拟机中的永久代)中没有垃圾收集的,Java虚拟机规范中说过可以不要求。在方法区中进行垃圾回收的性价比一般比较低。

永久代的垃圾收集只要是两部分:废弃常量和无用的类。

废弃常量:没有任何对象引用常量池中的次常量,也没有其他地方引用这个字面量。

无用的类:该类的所有的实例都已经被回收,即Java堆中不存在该类的任何实例;加载该类的ClassLoader已经被回收;该类对应的java.lang.Class对象没有在任何地方被引用,也无法通过反射来访问该类。

 

本章节介绍了对象死亡的判定,以及如何进行回收,以及垃圾收集的算法,内容参考来自《深入理解Java虚拟机》,下一章节介绍各个垃圾收集器。如有错误,敬请指出,谢谢

 

Java核心技术系列Java虚拟机规范Java SE 8版)》由Oracle官方发布,Java虚拟机技术创建人撰写,国内资深Java技术专家翻译。书中基于全新Java SE 8,完整且准确地阐述Java虚拟机规范,是深度了解Java虚拟机Java语言实现细节的必读之作。   《Java核心技术系列Java虚拟机规范Java SE 8版)》共分7章。第1章从宏观的角度介绍了Java虚拟机Java的关系及发展历程;第2章概述Java虚拟机的整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据区、栈帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助;第3章详述如何将Java语言编写的程序转换为Java虚拟机指令集,涉及常量、局 部变量、控制结构、算术运算、参数接收、方法调用、数组、操作数栈、异常处理、同步与注解等;第4章深入分析用来表示编译后的类和接口的class文件格式;第5章定义Java虚拟机启动以及类与接口的加载、链接和初始化过程;第6章阐释并列举Java虚拟机指令集;第7章提供一张以操作码值为索引的Java虚拟机操作码助记符表。   《Java核心技术系列Java虚拟机规范Java SE 8版)》完整而准确地阐释了Java虚拟机各方面的细节,围绕Java虚拟机整体架构、编译器、class文件格式、加载、链接与初始化、指令集等核心主题对Java虚拟机进行全面而深入的分析,深刻揭示Java虚拟机的工作原理。同时,书中不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件中各属性的含义,以及字节码验证的规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值