JAVA提高(五)--- GC部分

1、标记算法。

一个对象被判定为垃圾的标准:看该对象有没有被其他任何对象引用
(一)引用计数算法:判断对象的引用数量来决定对象是否可以被回收。每个对象实例都用一个引用计数器,初始值为1,被引用则+1,完成引用则-1。任何引用计数为0的对象实例就可以被视为垃圾。
优点:执行效率高,程序执行受影响较小。
缺点:无法检测出循环引用的情况,导致内存泄漏。
(二)可达性分析算法:判断对象的引用链是否可达来决定对象是否可以被回收。
GC Root:
(1)虚拟机栈中的引用对象
(2)方法区中的常量引用对象
(3)方法区中的类静态属性引用对象
(4)Native方法的引用对象
(5)活跃线程的引用对象

2、回收算法与GC分类

算法:
(一)标记-清除算法:对对象进行可达性分析算法标记垃圾对象,对堆内存从头到尾进行线性遍历,回收不可达对象内存。
缺点:碎片化严重,可能导致以后要保存较大对象时,没有连续内存,而不得不额外触发一次垃圾回收。
(二)复制算法:将可用的内存分为两块,一快为对象面,一块为空闲面,对象创建在对象块。如果对象块存满了,将还存活这的对象从对象面复制到空闲面,然后将对象面所有对象内存清除。(适用于对象存活率低的情况,比如年轻代)
优点:解决了碎片化问题;顺序分配内存,见到高效。
缺点:对于存活率高的对象,复制效率太低,而且浪费了一半的内存资源。
(三)标记-整理算法:对对象进行可达性分析算法标记垃圾对象,移动所有存活的对象,按照内存顺序依次排列,然后将末端内存地址以后的内存全部回收。(适合存活率高的场景,比如老年代)
优点:避免内存的不连续性;不用设置两块内存互换。
(四)分代收集算法:按照对象生命周期的不同划分区域采用不同的垃圾回收机制(提高垃圾回收效率)
分类:
(一)Minor GC:年轻代中的垃圾收集动作,使用复制算法。年轻代要尽可能快速的收集那些生命周期短的对象。
在这里插入图片描述
1.新对象生成在Eden区域,年龄为0。装满Eden后,将存活对象复制到from中并且年龄+1,然后清空Eden。
2.Eden区域再次满了之后,将存活对象和from中的存活对象都复制到to中且年龄+1,然后清空Eden和from。
3.依次循环,当对象年龄达到某个值时(默认15岁,可以-XX:MaxTenuringThreshold改变),这些对象就会成为老年代。
注:如果对象太大,eden和survivor装不下,就会直接进入老年代。
常用调优参数:
-XX:SurvivorRatio:Eden和Survivor的比例
-XX:NewRatio:老年代和年轻代内存大小比例
–XX:MaxTenuringThreshold:年轻代到老年代的年龄定值
(二)Full GC:采用标记-清楚或者标记-整理算法。触发Full GC条件:
1.老年代空间不足;
2.CMS GC时出现promotion failed(进行minor GC时,survivor装不下了,对象放入老年代,但是老年代也放不下了),concurrent mode failure(在执行CMS GC时,有对象要放入,但是老年代内存不足);
3.老年代剩余空间小于Minor GC晋升到老年代的平均大小;
4.程序用调用System.gc,只是提醒该回收了,系统不是一定执行。

3、年轻代垃圾收集器

Stop-the-World:JVM由于执行GC而停止与GC无关的线程,任何一种GC都会发生。多数GC优化通过减少Stop-the-World发生的时间来提高程序性能。
Safepoint:保证GC过程中,没有对象引用关系变化,需要在某个节点有确定性,这就是安全点。当线程跑到安全点时冻结所有它,所有线程都到达安全点时,冻结所有,进行GC。产生安全点的地方:方法调用;循环跳转;异常跳转等。
JVM运行模式:Server启动速度慢,重量级虚拟机,启动稳定后程序运行速度比Client快。Client启动速度快,轻量级虚拟机。使用java -version查看JVM运行模式。
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)

(一)Serial收集器(复制算法):单线程收集,垃圾收集时暂停所有其他工作线程。简单高效,Client模式下默认的年轻代收集器。
(二)ParNew收集器(复制算法):多线程收集,其他行为与Serial一样。Server模式下虚拟机首选的年轻代收集器。单核执行效率不如Serial,因为线程交互需要开销。多核下才有优势。
(三)Parallel Scavenge收集器(复制算法):与ParNew收集器类似,不过比起关注用户停顿时间,更关注系统的吞吐量,一般用于不怎么交互的后台处理。Server模式下默认的年轻代收集器。

4、老年代垃圾收集器

(一)Serial Old收集器(标记-整理算法):Serial收集器的老年代版本。简单高效,Client模式下默认的老年代收集器。
(二)Parallel Old收集器(标记-整理算法):多线程,吞吐量优先。
(三)CMS收集器(标记-清除算法):1.初始化标记:Stop-the-World,从根对象开始,只扫描到能与根对象直接关联的对下 2.并发标记:并发追溯标记,程序不会停顿 3.并发预清理:查找执行并发标记时,从年轻代晋升到老年代的对象。 4.重新标记:Stop-the-World,暂停虚拟机,扫描CMS堆中剩余对象 5.并发清理:清理垃圾,程序不停止。 6.并发重置:重置CMS的数据结构,等待下次回收。

额外:Garbage First收集器的特点:(复制算法 + 标记-整理算法)
1.并发和并行,使用多个CPU减少Stop-the-World的时间
2.分代收集,能同时处理年轻代和老年代
3.空间整合,基于标记-整理算法
4.可预测的停顿,能让使用者设置垃圾收集时间最多花费多少毫秒。
贯穿年轻代和老年代,将整个Java堆内存划分为多个大小相等的Region,老年代和年轻代不再物理隔离。

5、常见问题

(一)Object的finalize()方法的作用是否与C++的析构函数作用相同:
答:不同,C++的析构函数调用是确定的,finalize是不确定的。当垃圾回收器宣布一个对象死亡时,需要两次标记。当对象进行可达性分析时,没有和GC Root相连接就会被第一次标记,并且判断是否执行finalize方法,如果对象覆盖了finalize方法且未被引用过就会放在F-Queue队列中,稍后由一个虚拟机自动建立的低优先级的线程去执行触发finalize方法。方法执行随时可能被终止。finalize是给予对象最后一次重生的机会。
(二)Java中的强引用,软引用,弱引用,虚引用有什么用:
1.强引用:最普遍的引用。如:Object obj = new Object()。如果内存空间不足,JVM会抛出OOM终止程序也不会回收具有强引用的对象。如果不使用对象了,要把对象设置为NULL来弱化引用,使其被回收。
2.软引用:表示对象处在有用但非必须的状态。内存空间不足时,GC会回收该对象。可以用来实现内存敏感的高速缓存。

String str = new String("abc");//强引用
SoftReference<String> softReference = new SoftReference<String>(str)//软引用

3.弱引用:表示非必须对象,比软引用更弱。GC一旦扫描到就会回收,但因为GC线程优先级比较低,被回收概率不大。适合用于引用偶尔被使用不影响垃圾收集的对象。

String str = new String("abc");//强引用
WeakReference<String> weakReference = new WeakReference<String>(str)//弱引用

4.虚引用:不能决定对象的生命周期,任何时候都可能被垃圾回收。主要拿来跟踪对象被垃圾回收的活动,起一个哨兵的作用。必须和引用队列联合使用。

String str = new String("abc");//强引用
ReferenceQueue queue = new ReferenceQueue();
RhantomReference rhantomReferenc = new RhantomReferenc(str, queue);//虚引用

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值