java垃圾回收机制

一直以来jvm对于我来说是既熟悉又神秘,本文给出我对于jvm的垃圾回收机制的一些理解。

1、什么样子的对象是垃圾,需要回收呢??

如果一个对象只有软引用或者弱引用来引用的时候,或者已经没有引用的时候,我们就说他是垃圾,需要被回收了,那么就有了第二个问题,怎么判断这个对象需要回收呢??

2、怎么判断一个对象需要回收呢??

以前的教科书都说采用了引用计数算法来判断对象是否存活,即:如果有一个地方引用这个对象,那么引用计数器的数值就加1,引用失效了,就减1,如果计数器的值为0,说明此对象已经死亡了,可以回收。但是,注意,有一种情况是有问题的,就是互相循环引用问题,如果两个对象循环引用,其实他们两个可以需要被回收,但是各自的引用计数器不为0,因此无法回收。

实际上,在主流的商用程序语言实现中,都是通过可达性分析算法来判断对象是否存活的。所谓可达性分析算法,就是说在GC roots节点开始,一直往下搜索,如果搜索不到,也就是不可达,那么就认为此对象是不可用的,就需要回收。
tips:如果一个对象被放入了F-Queue队列中,准备被回收时,他只能在finalize()方法中通过重新与引用链上的任何一个对象建立关联就可以了,但是任何一个对象的finalize()方法都只会被系统自动调用一次,如果下一次面临被回收,就没用了。

3、垃圾回收算法有哪些???

标记-清除算法:先标记那些需要回收的对象,然后标记完成后统一回收所有被标记的对象。主要用于老年代的垃圾回收中可能会造成大量的不连续的内存碎片!
标记-整理算法:先标记那些需要回收的对象,然后让所有存活的对象向另一端移动,然后直接清理掉端边界以外的内存。这也用于老年代的回收中。
复制算法:一般来说是将内存按照容量划分为2个大小相等的块,每次只使用其中的一块,如果一块用完了,那么上面还存活的对象复制到另一块中,然后一次性清理用过的那块,但是代价有点高,牺牲了内存的一半。因此现在的虚拟机都是将内存分为一块较大的Eden和两块较小的Survivor,每次使用Eden和其中一个Survivor空间,回收的时候就将上面存活的对象一次性的复制到另一个Survivor上,HotSpot默认Eden和Survivor的比例是8:1,因此也就是浪费了10%的空间。但是如果说对象存活的过多,还需要老年代进行分配担保主要在新生代中。
分代收集算法:现在的主流虚拟机都采用的是这种方法,就是根据对象的存活周期来将内存分为了新生代和老年代。

4、HotSpot的算法是怎么实现的???

主要是利用一个叫做OopMap的数据结构来快速且准确的完成GC Roots枚举,但是不可能HotSpot为每一条指令都生成OopMap,因此引用了一个叫做安全点的概念!!只有到达了安全点,GC才会开始执行。安全点的选取应该以“是否具有让程序长时间执行为特征”,主要就是方法调用,循环,异常跳转等。主要用主动式中断的方法让所有的线程跑到安全点的附近停下来。也就是设置了一个标志,各个线程主动去轮询这个标志,如果中断标志是真那就停下来了。如果有些线程不执行了,比如sleep了,那读取不到标志怎么办呢???这时候就可以让这个线程标识自己进入了安全区域了,GC就不会管他,开始high起来了~~~~

5、垃圾收集器有哪些呢????

Serial:**位于新生代中,在**jdk1.3中就有了,是最基本的收集器,他是一个单线程的垃圾收集器,不是说只使用一个cpu或者是收集线程进行垃圾回收,而是它在垃圾回收的时候,就会终止其他所有的线程,也就是“Stop the world”,采取的是复制算法。他简单高效,对于运行在client模式下的虚拟机来说很好
ParNew:他就是对应Serial的多线程版本,它的收集算法,对象分配规则,回收策略等和Serial都是一样的,是在Server下的首选的新生代收集器。
Parallel Scavenge收集器:这个收集器的着重点主要是在乎吞吐量。
Serial Old:位于老年代,对应Serial,采用的是标记-整理算法,也是单线程的。在Server中,他可以搭配PS或者CMS一起使用。
Parallel Old收集器:配合ps的。使用的算法是标记-整理算法。
CMS收集器以获取最短回收停顿时间为目标的收集器
大致流程是:初始标记并发标记重新标记并发清除
缺点:CMS收集器无法处理浮动垃圾会产生大量的碎片
G1:*特点并行和并发,分代收集,可预测的停顿*
大致流程:初始标记并发标记最终标记筛选回收
其中初始标记,筛选回收是需要停下来的。
tips:Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描。

6、内存是如何分配的???

对象在大多数情况下是在新生代Eden区进行分配,如果Eden中空间不够了,那么JVM就发起一次GC。
大对象(很长的字符串或者是byte[])直接让他们进入老年代,长期存活的也将进入老年代。

tips:虚拟机会给每一个对象定义一个对象年龄计数器,如果在Eden中出生并经过了第一次GC后还存活,并且被Survivor容纳,那么就会被移动到Survivor空间中,对象年龄就是1岁,他每熬过一轮的GC,就大一岁,当他老到一定的程度,就会被弄到老年代中。当然也有动态对象年龄判定:如果在Survivor空间中相同年龄所有对象大小的总和大于SurVivor的一半,年龄大于等于这个对象的就直接进入老年代。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值