2.JVM学习之垃圾回收

1.那部分内存需要回收?

因为虚拟机栈和程序计数器在程序编译时,已经大概计算出了需要多少内存空间,栈和程序计数器的内存随线程的销毁而回收,所以主要垃圾回收考虑的是堆和方法区。

2.引用计数算法

每个类实例定义一个计数指针,当引用到时计数加一,引用结束计数减一,当任何时间都没有引用时,则内存回收。虚拟机不用此方法,因为若两个类循环引用则这两块内存永远不能回收。

3.可达性分析算法(常用)

定义了许多GC roots即为根节点对象,从根节点开始查找引用(引用链),若有对象无法从根节点到达,则此类对象认为是可回收的。
GC roots有:
·在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、 局部变量、临时变量等。 (即栈里或某个线程直接引用了对象)
·在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。(方法区中定义的静态属性,用到了某个对象)
·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
·在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
·Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。·
所有被同步锁(synchronized关键字)持有的对象。(synchronized是否影响效率?)
·反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

根据回收区域划分,在根节点中可能还有用户的临时对象

4.引用类型

强引用、软引用、弱引用、虚引用;强弱关系依次降低
强引用:直接地址和对象内存位置的引用,一般不会被回收
软引用:当内存不够要溢出时,回收
弱引用:无论当前内存是否足够,垃圾回收时都回收
虚引用:不影响对象生存时间,为了在对象回收时有提示信息

5.垃圾回收的二次筛选

在GC roots与某个对象未产生引用链后,此对象被第一次标记,标记对象随后进行第二次筛选,是否执行finalize方法(此方法只执行一次),若没覆盖此方法和已经执行过,则无法执行。若有必要执行finalize方法,则会将这些对象放入一个队列中,并且创建一个finalize低调度的线程去调用他们的finalize方法,“执行”是指虚拟机会触发这个方法开始运行,但并不承诺一定会等待它运行结束。这样做的原因是,如果某个对象的finalize()方法执行缓慢,或者更极端地发生了死循环,将很可能导致F-Queue队列中的其他对象永久处于等待,甚至导致整个内存回收子系统的崩溃。此对象若在finalize重新与GC roots建立了引用链则不回收,若没有则被第二次标记回收。

6.方法区的垃圾回收

方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型。回收废弃常量与回收Java堆中的对象非常类似。
举个常量池中字面量回收的例子,假如一个字符串“java”曾经进入常量池中,但是当前系统又没有任何一个字符串对象的值是“java”,换句话说,已经没有任何字符串对象引用常量池中的“java”常量,且虚拟机中也没有其他地方引用这个字面量。
如果在这时发生内存回收,而且垃圾收集器判断确有必要的话,这个“java”常量就将会被系统清理出常量池。常量池中其他类(接口)、方法、字段的符号引用也与此类似。判定一个常量是否“废弃”还是相对简单,而要判定一个类型是否属于“不再被使用的类”的条件就比较苛刻了。
需要同时满足下面三个条件:
·该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
·加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、JSP的重加载等,否则通常是很难达成的。

·该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是“被允许”,而并不是和对象一样,没有引用了就必然会回收。
关于是否要对类型进行回收,HotSpot虚拟机提供了-Xnoclassgc参数进行控制,还可以使用-verbose:class以及-XX:+TraceClass-Loading、-XX:+TraceClassUnLoading查看类加载和卸载信息,其中-verbose:class和-XX:+TraceClassLoading可以在Product版的虚拟机中使用,-XX:+TraceClassUnLoading参数需要FastDebug版[插图]的虚拟机支持。
在大量使用反射、动态代理、CGLib等字节码框架,动态生成JSP以及OSGi这类频繁自定义类加载器的场景中,通常都需要Java虚拟机具备类型卸载的能力,以保证不会对方法区造成过大的内存压力。

7.垃圾回收算法?

垃圾回收算法可划分为两大类:“引用计数垃圾收集式”、“追踪式垃圾收集”,以追踪式垃圾收集为例
分代收集理论,即把堆空间分成新生代和老年代,老年代存储的是很长时间没有被回收的,所以回收一般是回收新生代。

8.垃圾回收效率如何提高?

根节点枚举(需要中断线程)-------如何中断线程?
数据加载完成时计算出偏移量、什么类型、记录栈和寄存器哪些位置在引用,oopMap数据结构存储,这样收集器在扫描时就可以直接得知这些信息了,并不需要真正一个不漏地从方法区等GC Roots开始查找。
不能每个指令都有oopMap结构记录,那样太消耗空间了。设置安全点在安全点记录这些信息,并进行垃圾处理。安全点的选定既不能太少以至于让收集器等待时间过长,也不能太过频繁以至于过分增大运行时的内存负荷。安全点位置的选取基本上是以“是否具有让程序长时间执行的特征”为标准进行选定的。
“长时间执行”的最明显特征就是指令序列的复用,例如方法调用、循环跳转、异常跳转等都属于指令序列复用,所以只有具有这些功能的指令才会产生安全点。

为线程设置标志位,线程找就近安全点暂停,如果有挂起线程,进入安全区域。等待回收完毕再出来
就好想在高速公路,开车,下达标志位命令通告所有车就近服务站停靠,但是总有些人不听话,直接拉去安全区域。等操作完毕再走。 线程不断轮询标志位。

记忆卡(卡表)就是讲老年代的引用区域再细分,分成一个个的卡页,某一页有对新生代的引用则变脏,怎么变脏?利用写屏障。

并发可达性分析:黑 灰 白三个点 开始全白,又根节点染黑的过程。(引用路径)
·白色:表示对象尚未被垃圾收集器访问过。显然在可达性分析刚刚开始的阶段,所有的对象都是白色的,若在分析结束的阶段,仍然是白色的对象,即代表不可达。
·黑色:表示对象已经被垃圾收集器访问过,且这个对象的所有引用都已经扫描过。黑色的对象代表已经扫描过,它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接(不经过灰色对象)指向某个白色对象。
·灰色:表示对象已经被垃圾收集器访问过,但这个对象上至少存在一个引用还没有被扫描过。

9.垃圾回收方式

标记 清除
标记 复制
标记 整理

什么样的要回收? 什么时候回收? 怎么回收? 怎么高效的回收?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值