JVM从入门到精通-垃圾回收-算法

为什么GC

1.什么是垃圾

面试题

 

垃圾:运行程序中没有任何指针指向的对象;

为什么需要GC

内存迟早会被消耗完,JVM将整理出的内存分配给新的对象;没有GC就不能保证营养程序的正常运行;

内存泄露:没有指针指向该对象;但也无法回收

 

JAVA垃圾回收机制

应该关心那些区域

主要是:堆和方法区

垃圾回收器:对年轻代,老年代回收;甚至对全堆和方法区回收;

频繁收集Young区,较少收集Old区,基本不动Perm区(或元空间)

 

throw是生成异常的过程;

throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常。

if(s.equals("abc")) { throw new NumberFormatException(); } else { System.out.println(s); }

 

throws 是方法可能抛出异常的声明;
throws:用在声明方法时,表示该方法可能要抛出异常,交给上层调用它的方法程序处理

public void function() throws Exception{......}

 

用try{…}catch{…}捕捉了异常之后一定要对在catch{…}中对其进行处理。

如果在函数体内用throw抛出了某种异常,最好要在函数名中加throws抛异常声明,然后交给调用它的上层函数进行处理。

 

垃圾回收的相关算法

1.标记阶段:引用计数算法

垃圾标记阶段:判断对象是否存活

垃圾:一个对象已经不再被任何的存活对象继续引用;

判断对象存活两种方式:引用计数算法和可达性分析算法

JAVA不使用引用计数器法:因为无法处理循环引用的情况;

循环引用

 

结论:

2.标记阶段:可达性分析算法(根搜索算法、追踪性垃圾收集)

 

GC Roots:根集合就是一组必须活跃的引用

GC Roots包含以下几类元素

1.虚拟机栈、本地方法栈或JNI引用的对象;

2.方法区中类静态属性引用的对象

3.方法区中常量引用的对象

4.所有被同步锁synchronized持有的对象

5.JVM内部引用:基本数据类型对应的Class对象,常驻异常对象,系统类加载器

本地代码缓存;

GC ROOTs:采用栈方式存放变量和指针;若一个指针,它保存了堆内存里面的对象,但自己又不存放在堆内存里,那它就是一个Root

 

STW的原因

3.对象的finalization机制

finalize:完成对象被销毁之前的自定义处理逻辑;

允许在子类被重写,用于在对象被回收时进行资源释放;

永远不要主动调用finalize方法;

1.在finalize时会导致对象复活;

2.finalize方法执行时间无法保证,由GC线程决定,可能不会执行;

3.糟糕的finalize会影响GC的性能;

 

由于finalize方法的存在:JVM的对象存在三种状态

1.可触及的

2.可复活的

3.不可触及的

finalize只会被调用一次

判断一个对象ObjA是否可以回收,至少要经历两次标记过程

例子:

总结

4.MAT与JProfiler的GC Roots溯源

获取Dump文件

方式1:命令行产生

方式2:JVisualVM导出

JVisualVM导出

1.选中当前进程

2.选择堆Dump

3.生成快照

4.存储Dump文件

5.用MAT查看Dump文件

 

5.清除阶段:标记-清除算法

5.1标记-清除(Mark-Sweep)算法

标记:非垃圾对象,标记可达对象;记录在对象的header中;

清除:对堆内存循环变量,发现非标记的对象,即不可达对象,则回收掉;

 

缺点:效率不高,要循环遍历;会产生内存碎片

清除:只是把清除的对象空间地址,存放在空闲列表中;下次使用时,可以直接覆盖;

 

6.清除阶段:复制清除算法

核心思想

把内存空间分为两块;

年轻代的S0和S1区就是使用的这种算法;

优点:不会产生碎片问题,创建对象时可以指针碰撞直接分配;

缺点:栈指针的引用改变为另一个区域,所以需要从新计算改变这些引用;

如图,对象地址改变,引用也需要改变;

注意:若内存中存活的对象比较多,则复制算法性能会下降,因为大部分对象都被复制移动了。

应用场景:

新生代的Survivor区,因为这个区域的对象都是朝生即死的;

不使用老年代,因为老年代的对象大部分都是存活的;

 

7.清除阶段:标记-压缩(整理)(Mark-Compact)算法

执行过程两个阶段:

1.标记阶段:标记所有存活的对象,即可达对象;

2.压缩阶段:压缩到内存一端,按顺序排放;

无需把内存分成两个区域;

标记-压缩算法:实际上是标记-清除-压缩算法;

只是它是非移动的回收算法(无需把内存分成两份),未解决压缩(移动时)仍要重新修改内存中引用地址的问题;wux

 

创建对象分配堆空间:

1.复制算法和标记-压缩算法,都可以使用指针碰撞;

2.标记-清除算法,可以使用空闲列表分配;

 

指针碰撞

 

8.总结

9.分代收集算法

具体分代算法

年轻代:使用复制算法;S0,S1;

老年代:是由标记-清除和标记-压缩混合实现

10.增量收集算法、分区算法

这两种算法主要是解决STW(Stop World)

10.1增量收集算法

增量收集、分区与其他传统算法交替执行;需要解决线程间冲突的问题;

低延时并行处理;

缺点:

10.2分区算法

说明

 

分区算法把内存分成一个一个小region;每次回收有时间限制,时间长多回收几个区域;时间短少回收几个区域。 

最后:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值