JVM知识体系总结3——垃圾回收

3 篇文章 0 订阅

       运行时区的堆是平时我们创建的的对象存放的空间,那么垃圾回收就是释放垃圾占用他的空间,防止内存泄露。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

1,何为垃圾对象,垃圾对象就是已经死亡的或者长时间没有使用的对象,那么如何一个对象是否存活了?

引用计数法:原理是设置一个计数器,有引用+1,引用失效-1,计数器为0则没有被引用,被GC,缺陷就是无法解决循环引用,如同死锁,A引用B,B引用A 、 

可达性算法:原理从一个叫GC Roots的对象开始向下查,如果找到这个对象就不是垃圾对象,如果没有就是垃圾对象,可以作为GC Root的对象有:虚拟机栈中引用的东西,方法区类静态属性引用的对象和方法区常量池引用的对象,本地方法站JNI引用的对象。这种方法就存在执行效率的问题,因为这种算法从GC ROOTS节点找引用链,如果引用的比较复杂就要逐个检查里面的引用,这样的话就会消耗很多时间,而且为了保证整个分析执行期间不产生新的引用,系统将会被冻结,导致执行的线程停顿,也就是所谓的SWT(stop  the world)。为了解决这些问题jvm使用了这些方法。使用跟节点,用一组OopMap的数据结构来存放对象的引用,这个 数据结构在类加载完成的时候就已经计算出来了,GC在扫描的时候就会得知这些信息,从而降低GC Roots时间以及减少停顿时间。OopMap中的引用关系变化或者OopMap的指令太多反而需要跟多的空间,所以OopMap会根据虚拟机选定的安全节点(也就是执行到哪一行)内去生成指令的OopMap在GC的时候,驱使所有的线程都跑到这个最近的节点。STW才发生,应用停顿。对于挂起的线程来说,比如sleep状态的,是不能跑到安全节点,那么这个时候就是增大安全域,如果线程达到安全域,就做一个标记,不需要管这些线程

 

2java中的强引用,软引用,弱引用,虚引用

 

如果一个对象被标记没有被引用了,还要进行一次赛选,判断这个对象是不是要装修finalize()方法。如果对象没有覆盖finalize()或者已经被虚拟机调用过。如果这个对象没有,这个对象就会被放进F-Queue的队列里面去,虚拟机会触发一个Finalize()的线程去执行。在finalize() 方法执行的同时,可以在执行方法内部,再次对对象进行引用,那么对象就不会被垃圾回收

 

3,内存泄漏和内存溢出

内存泄漏:一个对象一直被占据在内存中,无法被回收,长生命周期的对象持有短生命周期对象的引用的时候就可能会发生,因为短生命周期对象已经不需要了,但是长生命周期还在引用他就导致都不能被回收,创建一个对象以后一直不在使用这个对象

内存溢出:新对象加入,内存空间不够,导致程序无法执行OOM

 

4,常见的几种GC方式

Minor GC:发生在新生代的GC,对象优先进入Eden区进行分配,当Eden区没有足够的空间进行分配的时候,jvm就会执行一次Minor GC,这个区的对象生存周期短,发生GC频率高,回收速度快。所以 Minor GC非常频繁,一般回收速度也比较快。

Major GC:   发生在老年代的GC,大对象和

长期存活的对象直接进入老年代。出现了Major GC会伴随至少一次的Minor GC。

Full GC:全局就行GC

 

5,堆内存的分配

 

新生代/年轻代 :年轻代主要存放新创建的对象,内存大小相对会比较小,垃极回收会比较须繁,年轻代分成1个Eden区和2个 Survivor区,当对象在堆创建时将进入年轻代的Eden区,垃圾回收器进行垃圾回收时,扫描 Eden和 Survivor (幸存区,如果对象仍然存活,则复制到 Survivor to,如果 from Survivor to已经满,则复制到 老年代,同时在扫描Survivor时,如果对象已经经过了几次的扫描仍然存活认为其为一个持久化对象,则将其移到老年代,扫描完毕后jvm将 Eden区和 to Survivor 区清空然后交换from和to的角色即下次垃圾回收时会扫描 Eden 区和 from Survivor区.这么做主要是为了减少内存碎片的产生年轻代垃圾回收时,采用将存活对象复制到到空的 Survivor区的方式来确保尽量不存在内存碎片,采用空间换时间的方式来加速内存中不再被持有的对象尽快能够得到回收

老年代/年老代 :年老代主要存放JVM认为生命周期比较长的对象(经过几次的 年轻代的垃圾回收后仍然存在),内存大小相对比较大,垃圾回收也相对没有那么繁(如可能几个小时一次),年老代主要采用压缩的方式来避免内存碎片(将存活对象移动到内存片的一边,也就是内存整理),当然,有些垃极回收器(如CMS垃圾回收器)出于效率的原因,可能会不进行压缩

 

5GC垃圾收集的几种方法

         标记-清除:分标记和清除两个阶段,先标记出所有的需要回收的对象,在标记完成后统一回收所有被标记的对象,这是最基本的收集算法。他的缺点主要有两个,一个是效率问题,标记和清除的效率不高,一个是空间问题,标记清除会产生大量的空间碎片空间碎片太多导致分配较大的对象时候无法找到满足的足够打的连续内存,触发另一次的GC动作。这个算法是需要需要STW暂停掉整个应用,用户感知是很不友好的。

 

         复制:他将可用的内存容量划分为两个大小相等的两块,每次用掉其中的一块,当这块用完的时候就将这块上还存活的对象复制带另外一块上面去,然后在把老的一块内存清理掉,以此往复。这种算法只能适用于存活对象比较少的情况(新生代),但是这种方式,内存的代价太高,每次基本上都要浪费一般的内存。于是将该算法进行了改进,内存区域不再是按照1:1去划分,而是将内存划分为8:1:1三部分,较大那份内存交Eden区,其余是两块较小的内存区叫survivor区。每次都会优先使用Eden区,若Eden区满,就将对象复制到第二块内存区上,然后清除Eden区,如果此时存活的对象太多,以至于 Survivor不够时,会将这些对象通过分配担保机制复制到老年代中。)

https://img-blog.csdnimg.cn/20200503231107227.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R1c2hpaGFvNjI2,size_16,color_FFFFFF,t_70

 

         标记-整理:标记的过程和标记清除一样,但后续的操作不是直接对可以回收的对象进行清理,而是先对内存空间进行整理,让所有存活的对面向一端移动,然后在清理。主要用于存活对象比较多的情况(老年代)

 

         分代收集:对大多数对象的生命周期非常短暂,存活时间也非常短,并且不同的对象生命周期是不一样的,java堆分为老年代和新生代,这样就可以根据每个代的特点来采取最合适的收集算法,新生代里面每次GC都有大量对象死去,少量对象存活,所以采用复制算法,老年代里面的对面存活率很高,所以采用标记清除或者标记整理算法。这种算法其实是对上面三种算法的一种结合

 

6,按系统线程分收集垃圾

串行收集:使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。但是,其局限性也比即无法使用多处理器的优势,所以此收集适合单处理器机器,当然,此收集器也可以用在小数据量(100M左右)情况下的机器上。

并行收集:使用多线程处理垃圾回收工作,因而速度快,效率高。而且理论上CPU数目越多,越能体现出并行收集器的优势

并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收收工作时,需要停整个运行环境(STW),而只有垃圾回收程序在运行,系统在垃圾回收时会有明显的暂停,而且暂停时间会因为堆越大而越长回收器

 

7,垃圾回收处理器

收集算法是内存回收的方法论,垃圾回收处理器是垃圾回收的具体实现,不同的厂商会有很大的差别

Serial/Serial Old收集器串行收集器:是最古老,最稳定以及效率高的收集器,可能会产生较长的体顿,只使用一个线程去回收新生代、老年代使用串行收集器,新生代复制算法、老年代标记压缩:垃圾收集的过程中会 STW

ParDew收集器其实就是串行收集器收集器的多线程版本用户线程需要等待(STW)

Parallel/Parallel Old收集器:类似于ParDew收集器, Parallell收集器更关注系纯的否吐量,可以通过参数来打开适应调节策略,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的体顿时间或最大的吞吐量;也可以通制GC的时间不大于多少毫秒或者比例:新生代复制算法、老年代标记压缩

CMS( Concurrent Martweep)收集器:是一种以获取最短回收仰时间为目标的收集器.目前很大一部分的Java应用都集中在互联网站成B/S系统的服务上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以始用户带来较好的体验,从名字(包含“ Mark Sweep)上就可以看出CMS收集器是基于标记-清除 算法实现的。优点:并发收集、低停顿。缺点:使用标记清除算法产生大量空间碎片、并发阶会低吞叶刘CPU资源敏感无法收集浮动垃圾需要预国一部分内存在GC的时候供程序运作如果预留空间不足可能会出现” Concurrent Mode Failure失败而导数触发一次Full GC。步骤:初始标记,并发标记,重新标记,并发清除

G1是目前技术发展的最前沿成果之一, Hotspot开发团队赋予它的使命是未来可以换掉JDK15中发布的CMS收集CMS收集器相比G1收集器有以下特点:1.空间整合,G1收集器采用标记整理算法,不会产生内存空间碎片。分配大对象时不会因为无法找到连续空间而提前触发下次GC,2.可预测停顿,这是G1的另一大优势,降低停顿时间是G1和cMs的共同关注点,但G1除了追求低停顿外,还能建立可测的伸顿时间模型,能让使用者明确指定在一个长度为M秒的时间片段内,消耗在垃圾收集上的时间不得超过N秒其他的垃圾收集器,收集的范围都是整个新生代或者老年代,而G1不再是这样,使用G1收集器时堆的内存布局其他收集器有很大差别,它将整个Java维划分为多个大小相等的独立区域( Region),虽然还保留有新生代和老年代的概念,但生代和老年代不再是物理隔阂了,它们都是一部分(可以不连续) Region的集合,优点:并与并发、分代收集、空问整合、可预测停镜。步骤:初始标记,并发标记,最终标记,筛选回收

新生代 :Serial, ParNew, Parallel, G1

年老代:CMS, Serial Old, Parallel old,G1

组台方式:Serial CMS,Serial Serial Old,ParDew CMS,ParNew+ Serial Old,Parallel Scaveage+ Serial old,Parallel Scaveage+ Parallel Old,G1+G1

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上士闻道,勤而行之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值