您的位置:首页 > 编程语言 > Java开发

深入理解Java虚拟机 读书笔记 之 对什么东西进行垃圾回收

2016-10-20 00:00 393 查看
对什么东西垃圾回收?

(1)垃圾回收的内存区域,堆与方法区

对于运行时的虚拟机栈、本地方法栈、程序计数器这3个区域,首先,这些区域在类在编译完了之后,其占用内存大小就已经固定,最关键的是,因为整个栈帧随着方法的结束,其生命周期也就结束了,因此这3个区域不用过多考虑内存回收的问题。

对于堆与方法区,java堆与方法区只有在运行时我们才知道其所占用的大小,这部分的内存分配与回收都是动态,是我们主要考虑的地方。

(2)已死的对象,引用计数法和可达性算法

垃圾回收器在对堆进行回收之前,第一件事情就是要判断一个对象是否已死?

引用计数法,大致思想是,一个对象如果被引用了一次就将这个对象的计数+1,如果引用失效则-1,当这个计数为0时,在垃圾回收的时候,就有可能会被回收,但是在java中如果采用这样一种回收方式,比较难以避免循环依赖的问题。因此HotSpot实现的JVM并不是采用这样一种方法。

可达性算法,大致思想是,从GC Root对象开始出发找寻其它对象,对于那些通过GC Root对象不可达的对象,则是需要回收的对象,那么问题来了,什么是GC Root对象。

GC Root对象包括,虚拟机栈(栈帧中的局部变量表)中引用的对象、本地方法栈中引用的对象、方法区中常量与静态属性引用的对象。

(3)不同的引用分类,强引用、软引用、弱引用、虚引用,导致回收的策略不同

引用,JVM中,找到一个对象,可以通过一个对象的句柄或者直接内存地址。通过句柄访问的好处,在垃圾回收的时候,不需要修改用户使用的指针,直接修改句柄指向的地址。通过直接内存访问的好处,就是快。在JDK1.2之前,Refrence的定义为,如果一个reference类型的对象里面存储一个指向其它地址的指针,那么这个就是一个引用。要么是,要么不是。我们希望描述这样一类对象,当内存空间还足够时,则能保留这个对象;如果在虚拟机执行了垃圾回收之后,内存依然比较紧张,则可以抛弃 这些对象。很多系统的缓存功能都符合这样的应用场景(?需要确认一下哪些场景,待补充?)。JDK1.2之后,扩张了引用的概念。

强引用,类似于 Object o = new Object(),这样的,无论什么时候,都不会被垃圾回收掉。

软引用,SoftRefrence对象,有用但是非必需的,在内存溢出之前,会对这类型的内存进行第二次回收,假如这个时候,依然没有足够的内存使用,则发生内存溢出。

弱引用,WeakRefrence对象,有用但是非必需,强度比软引用更弱。该类型的对象只能活到第二次垃圾回收之前,在第二次垃圾回收之前,不管内存是否够用,都会回收。

虚引用,对其什么周期完全没什么影响,但是会在回收的时候,惟一目的就是这个对象在垃圾回收的时候,会收到系统的一个通知。

(4)两次标记的回收过程

即使是可达性分析算法中不可达的对象,也不是”非死不可“。此时处于”缓行阶段“,要真正宣告一个对象的死亡,至少需要2次标记过程。
如果对象在可达性分析算法分析后,发现没有与GC Roots 相连接的引用链,那它会被第一次标记,并且进行一次筛选。筛选的条件是这个对象是否有必要执行finalize()函数。对于那些finalize()方法已经被虚拟机执行过的,或者finalize()方法没有被覆盖的,这两张任意一种都不必要执行。

如果对象被判定为需要执行finalize()方法,那么这个对象会被放到F-queue队列中,JVM会启动一个低优先级Finalizer线程去执行队列中对象的finalize()方法。稍后会进行第二次标记,如果在执行finalize()方法的时候,重新将这个对象与引用链上的对象关联,则在标记时,会把这个对象从即将回收的集合中移除。

(5)方法区的回收

JVM中的永久代(方法区是存在这个区域的)也是会进行垃圾回收的,包括那些废弃常量与废弃的类。废弃的类的判断:这个类的所有实例都已回收,加载该类的classloader已经被回收,该类对应的java.lang.Class对象没有任何地方被引用,无法在任何其它地方使用反射来访问该类中的方法。在大量使用代理、CGLib、反射、频繁使用classloader的地方都需要考虑永久代的回收
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JVM