JAVA垃圾收集机制
2015-11-19 23:03
585 查看
一。哪些内存需要回收:
java使用的不是引用计数法。如果两个对象互相引用,引用计数不为0,那么就无法回收这些对象。
java使用的是:可达性分析(Reachability Analysis),这个算法的思想是通过一系列的称为“GC Roots”的对象作为起点,从这些起点开始往下搜索,搜索走过的路径称为引用链,当一个对象到GC
Roots没有任何的引用链,相连接时,则证明这个对象是不可引用的。
可以作为GC ROOT的对象可以包括以下几种:
1.虚拟机栈中引用的对象
2.方法区中类静态属性引用的变量
3.本地方法区中常量引用的变量
4.本地方法栈中JNI(及一般说的Native方法)引用的对象。
二、被标记需要清除对象的自我救赎
上一章讲了java垃圾收集机制是基于 GcROOT可达性分析,那么这章要说的是,即使没有通过可达性分析的对象,也并非是“非死不可”。第一轮筛选:如果对象在可达性分析中没有于GcROOT链相连,那么就需要进行第二轮筛选
第二轮筛选:对象有没有覆盖(override)过 finalize()函数,对象是否还没运行过finalize()函数。如果这连个条件都满足,
那么对象就会判断为有必要执行finalize()函数,并把这个对象放入到一个叫做F-Queue的队列中,
稍后GC会对这个队列中的对象进行第二次扫描,执行每个对象的finalize()函数,那么如果对象要在这里拯救自己——只要在finalize()函数中让自己重新与GcROOT的任何一个对象建立连接即可。
譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在这第二次筛选中就会将这个对象移出出“即将回收”的集合。
如下代码:
package test; public class FinalizeEscapeGC { public static FinalizeEscapeGC SAVE_HOOK = null; public void isAlive(){ System.out.println("the object is alive"); } protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize method is excuted"); FinalizeEscapeGC.SAVE_HOOK = this; } public static void main(String[] args) { SAVE_HOOK = new FinalizeEscapeGC(); SAVE_HOOK = null; System.gc(); try { //因为finalize方法的优先级很低,所以等待0.5秒以等待它 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } if(SAVE_HOOK != null){ SAVE_HOOK.isAlive(); } else { System.out.println("no , I am dead"); } } }
最后运行的结果是:
finalize method is excuted
the object is alive
可以看到最后这个对象自我拯救成功。
三、垃圾收集的算法
上一章我们讲了一个对象要确认被垃圾回收,需要经过两次筛选 1:GCROOT可达性分析,2:对象是否在finalize()方法中自我拯救。那么这一章将具体介绍一下垃圾收集的算法1.标记-清除 算法
①标记出所有需要回收的对象。
②标记完成后,统一回收所有被标记的对象。
缺点是:①:标记和收集的两个过程效率都不高。②:标记清除后会产生大量的不连续的内存空间,空间碎片多了以后就无法分配大块的内存空间给大的对象使用。
标记清除算法:
2.复制算法:
将内存分为大小相同的两部分,只在其中的一部分内分配内存,当这一部分内存用完需要垃圾回收的时候,就将这部分内存中还存活的对象复制到另一部分内存中。然后再将使用过的这部分内存一次性清空。就是对整个半区进行回收。
内存回收前:
内存回收后:
那么这种复制算法的好处就是 高效,也不用考虑内存碎片等复杂的问题。
缺点就是每次只能使用一半的内存,未免太浪费了。好消息是,对于新生代的对象来说大部分都是很快就死去了,所以剩下存活的对象寥寥无几,所以我们没有必要按1:1的比例来分,HotSpot虚拟机的默认分配比例是8:1
3.标记——整理算法:
我们上面介绍的 复制算法 在对象存活率较高的情况下就要进行较多此的垃圾回收,显然不适合,那么对于对象存活率较高的情况 我们可以使用另外一种算法:
标记——整理算法。其中标记过程和我们介绍的第一个“标记——清除”算法一样。但是后续步奏不是直接对对象进行回收,而是让所有存活的对象都向其中的一端移动,然后直接清除掉端边界外的内存。
那么介绍完上面这些收集算法之后,我们要知道它们在java虚拟机中使用的地方是不一样的。
java一般将内存分为 新生代 和 老年代
新生代对象的存活率低,可以使用 复制算法 回收内存
而老年代的对象存活率高,可以使用 标记——整理 算法来回收内存
参考书本:《深入理解Java虚拟机 JVM高级特性与最佳实践》更详细内容,请参考书本
相关文章推荐
- 扫描枪自带回车的Java模拟
- JavaWeb---框架SpringMvc+Mybatis开发项目第二季(共三季)
- 《JAVA 程序性能优化》读书笔记:木桶原理与性能瓶颈
- 简单选择排序Java实现与分析
- java取得当前工作目录
- Java字符串String中contains与indexOf的区别
- Set接口
- Java中设置方法执行的超时时间
- HashMap死循环问题分析
- java基础 7种反转方法 charAt()等方法
- java连接mysql与简单操作mysql的增删改查简单例子
- 4. Spring 4.2.3前瞻-使用@Order调整配置类加载顺序
- 关于java实例化学习
- java静态和非静态代码块的执行顺序
- 3. Spring 4.2.3前瞻-@Import注解的升级
- Java异常分类
- 2. Spring 4.2.3前瞻-对java8默认方法(default method)定义Bean的支持
- MyEclipse提示键配置、提示快捷键、提示背景色、关键字颜色、代码显示、编...
- gradle eclipse下构建ssh2项目
- 从头认识java-9.10 Map