简单了解GC垃圾回收

如何判断数据是垃圾数据?

1.引用计数算法
为对象添加引用计数器,当计数为0时,被标记为垃圾对象,可以被回收。
优点:原理简单,实现方便,性能较高。

2.可达性分析法
判断对象和GC ROOTS是否有相连的引用链,如果没有,则标记为垃圾对象
GC ROOTS对象 都是常用的有用的对象
1)虚拟机栈(栈帧中的本地变量表)中引用的对象。
2)方法区中类静态属性引用的对象。
3)方法区中常量引用的对象。

如何清理垃圾数据?

1.Mark-Sweep标记清除算法
优点:原理简单,回收高效
缺点:回收之后,会产生大量不连续的内存碎片,导致内存的环境质量下降
如果内存碎片过多,可能会导致分配较大对象找不到足够的连续的内存地址空间,所以会提前触发另外一次GC,而这一次GC很可能是Full GC(全堆GC),导致性能下降,因为Full GC 的时间是很长的
GC调优的目的之一:尽可能减少Full GC的触发

2.Copying复制算法
将可用内存空间划分,每次只使用其中一块,当GC时,将存活对象复制到另外一块,然后再进行清理.
优点:可以避免产生大量的内存碎片
缺点:内存的利用率比较低,只有50%

3.Mark-Compact标记整理算法
可以用此算法回收老生代
优点:不会产生内存碎片
缺点:比Mark-Sweep算法慢,因为要做碎片整理
即回收老生代的选择:Mark-Sweep,Mark-Compact

注意:
1.新生代中的对象多活几次后(默认是15次)可以晋升到老生代
2.新生代的GC频率高,老生代的GC频率低
3.新生代的GC称为Minor GC
4.老生代的GC称为Major GC(Full GC)

由垃圾回收器回收垃圾

在这里插入图片描述
上图中,如果收集器之间有连线,表示可以一起使用。

1.Serial系列收集器
特点:单线程收集器,并且在回收垃圾时必须停掉所有的工作线程,且停顿时间长,用户体验很差
目前Serial可以用于桌面系统的垃圾回收.因为垃圾量比较小,回收间隔比较短

2.ParNew
特点:多线程收集器,所以回收速度要快于Serial,并且停的时间要比Serial更短,此外,ParNew可以和CMS收集器一起使用

3.CMS Concurrent Mark Sweep收集器
并发低停顿收集器
特点:这款收集器在做垃圾回收时,停顿间隔最短
CMS将回收过程分为四个阶段:
1)初始标记(CMS initial mark)
2)并发标记(CMS concurrent mark)
3)重新标记(CMS remark)
4)并发清除(CMS concurrent sweep)
注意:
1,3阶段会产生停顿
2,4阶段和用户工作线程一起并发工作
CMS将产生停顿最长的阶段(清除阶段)设计为并发机制,所以极大的减少了停顿时间,而1,3阶段即使产生停顿,也仅仅是扫描一下对象的引用链,所以停顿极端
回收垃圾示意图如下
在这里插入图片描述
CMS在清除垃圾时,可以配置多个线程,进一步加快回收效率
CMS优点:
回收停顿时间最短
CMS缺点
1.可能会产生浮动垃圾,需要等到下一次才能收掉
2.清除阶段,垃圾回收线程和用户线程一起工作,共同抢占CPU时间片,可能会降低工作线程的效率
3.CMS在回收垃圾时,用的是Mark Sweep标记-清除算法
所以需要定期的做碎片整理

4.Parallel系列
特点:多线程收集器,并不关注回收器的停顿时间,而是关注垃圾回收的吞吐量

5.G1 GC
G1 GC改变了传统思路,没有将整个堆划分为新生代和老生代,而且通过区域块来处理,区域块大小可配置,1MB~32MB
优点:
1.内存的利用率极高(整堆),可以避免内存浪费,比如传统思路下,新生代内存紧张而老生代空闲的资源浪费情况
2.G1 GC底层会发生Minor GC 和Full GC两种GC,会发生Full GC的条件:整个堆找不到全空区域块时,才会发生Full GC,所以G1 GC发生Full GC的频次更低
3.G1 GC引入RememberSet机制,记录当前区域块对象的引用链关系,避免全堆扫描,性能更高.并且是每个区域块的GC更加独立

其他知识点:

1.Java 的垃圾回收机制是为所有 Java 应用进程服务的,而不是为某个特定的进程服务的。因此,任何一个进程都没有权利去命令垃圾回收机制做什么、怎么做或做多少。
Java 运行时系统只在需要的时候才使用垃圾收集。因此用户无法知道垃圾回收发生的精确时间。同样没有办法预知在一组均符合垃圾收集器收集标准的对象中,哪一个会被首先收集。

2.系统方法-finalize
JVM垃圾收集器收集一个对象之前,一般要求程序调用适当的方法去释放资源,但是在没有明确释放资源的情况下,java提供了缺省机制来中止化该对象释放资源,这个方法就是finalize()

finalize()的执行过程
一个对象真正死亡,至少要经过两次标记过程,如果对象不可达,那么它会被第一次标记并且进行一次筛选。筛选的过程就是该对象是否需要执行finalize()方法。如果该对象没有覆盖该方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为没有必要执行。
finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那么基本上它就真的被回收了。
finalize()并不是必须要执行的,它只能执行一次或者0次。如果在finalize中建立对象关联,则当前对象可以复活一次。

finalize方法是Object提供的的实例方法,使用规则如下:
当对象不再被任何对象引用时,GC会调用该对象的finalize()方法
finalize()是Object的方法,子类可以覆盖这个方法来做一些系统资源的释放或者数据的清理
可以在finalize()让这个对象再次被引用,避免被GC回收;但是最常用的目的还是做cleanup
Java不保证这个finalize()一定被执行;但是保证调用finalize的线程没有持有任何user-visible同步锁。
在finalize里面抛出的异常会被忽略,同时方法终止。
当finalize被调用之后,JVM会再一次检测这个对象是否能被存活的线程访问得到,如果不是,则清除该对象。也就是finalize只能被调用一次;也就是说,覆盖了finalize方法的对象需要经过两个GC周期才能被清除。

3.System.gc-程序员建议清除
垃圾收集器不可以被强制执行,但是程序员可以通过system.gc()方法去建议执行垃圾收集器

4.GC回收的对象
垃圾回收主要发生在线程共享的方法区和java堆中
本地方法栈(线程私有的),程序计数器(线程私有的),虚拟栈(线程私有的)随线程的启动而产生,随线程的消亡而清除
 方法区是所有线程共享的一片内存区域。它存储的是已被JVM加载的类信息,常量,静态变量,编译器编译后的代码等数据。在JDK1.8以前的HotSpot虚拟机中,方法区也被称为永久代,1.8后被元空间取代。
 方法区称为永久代并不意味这进入方法区就永久存在,方法区也会发生内存回收,此区域的内存回收主要是针对常量池的回收以及对类型的卸载。
根据Java虚拟机规范规定,堆内存需要在逻辑上是连续的(在物理上不需要),在实现时,可以是固定大小的,也可以是可扩展的,目前主流的虚拟机都是可扩展的。如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java heap space异常。

5.GC回收的过程
1).首先是程序先启动,堆内存就开始开辟空间,由GC(Garbage Collector)来检测堆内存的使用情况。程序启动的时候,GC也就启动了,就开始去监测堆内存的使用情况,如果堆内存的使用率超过了0.75就开始通知垃圾回收,具体的还是系统-system.gc(),程序员决定不了什么时候进行垃圾回收
2).创建出来的新对象会存放在新生代伊甸园区,此时GC会进行扫描,如果扫描到这个对象已经不再使用就会把对象清除,如果还在使用就把这个对象移动到新生代的幸存区,还是会进行多次扫描,如果这个对象不再使用就会清除,如果还在使用就会把这个对象移动到老生代,在进行扫描,扫描的频率没有新生代的高,也会进行扫描,如果扫描到了这个对象不在使用的时候就会清除,如果还是一直使用就会放入老生代,如果清除了老生代的对象,可能就会造成系统崩溃

6.当新创建的对象很大时GC回收垃圾的过程
先把这个新对象放入新生代的伊甸园区,放入失败,就会对新生代进行一次初代回收
再次放入新生代,放入失败,在对新生代进行第二次初代回收
再次放入新生代,放入失败,把该对象放入老生代,放入失败,则进行完全回收
在吧这个对象放入新生代,放入失败,就对新生代进行第三次初代回收,再放入新生代
放入失败,把这个对象放入老生代,放入失败,针对老生代进行第二次完全回收
新对象再次往新生代存储,放入失败,移动到老生代进行存储,放入失败-报错(内存溢出异常)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值