jvm垃圾回收分析

本文主要针对Java 堆内存划分,GC垃圾回收做一个简单的介绍

1:首先说一下确认对象死亡的方法有:

a:引用计数法--- 一个对象每被一个对象引用计数+1 。

b:可达性分析法--- 从GC ROOT往下索引能够索引到该对象则表示可达,即该对象依然有被引用到,表示存活

2:回收算法有:

a:标记-清除法 ,即标记出死亡的对象,然后将标记的对象直接回收掉。优点在于快,缺点在于制造出很多的内存碎片,有可能造成进行大对象时没有连续空间分配而导致再次GC。


b:复制算法:例如将内存分为两块,其中一块用于分配内存来存储对象,另一部分空着。在GC的时候确认哪些对象存活的,把它们移到另外一块内存区域中,然后将原先那块内存全部回收。这样的好处就是没有了内存碎片且相对高效,缺点就是内存变小了一半


c:标记-清理:将存活的对象移动到一端,然后记录边际区域,对边际区域外的内存进行回收。好处在于不生成碎片,坏处在于成本比较高。


3:堆内存被粗略的划分为新生代跟老年代,如图所示,Eden区跟TO,FROM区统称为新生代,默认情况下Eden:TO:FROM = 8 : 1 : 1,可通过参数配置。Old则表示老年代


绝大多数对象被实例化的时候都会分配在Eden区(某些大对象直接分配到Old区,可通过参数设置限制值)。因为绝大多数的对象都是朝夕朝灭,在使用一次后很快就死亡的。所以新生代区使用的是复制算法进行垃圾回收,当发生一次GC时Eden跟FROM(或者TO)中存活的对象会移动到TO(或者FROM)中,然后对Eden跟FROM(或者TO)中的内存进行回收。当TO中的内存不够存放存活对象时则会将他们转移到OLD中。

当对象在新生代中经过多次GC(默认好像是10次)后依然存活则会将其转移到老年代。老年代中使用的回收算法有标记-清理跟标记-清除,主要看收集器的实现。


4:新生代收集器

a :serial收集器:单线程,需要stop the world(即回收的时候其他线程都必须暂停)

b :parNew :可以看做是serial的多线程版本~在多CPU环境下性能会高于serial,但是少CPU环境下性能反而低于serial,比较牵扯到各种线程间的调用

c :Parallel Scavenge :多线程并发的收集器,跟serial,parNew这些以减少停顿时间为目的的收集器不同,它专注于提高系统吞吐量

5:老年代收集器

a:serial old:使用标记-清理

b:Parallel old :专注吞吐量

c:CMS:使用标记-清除算法,一个比较牛掰的收集器。CMS收集器分4个步骤:1,初始标记 2,并发标记 3,重新标记 4,并发清除 耗时最长的并发标记和并发清除都可以与用户线程一起工作了。 还有三个缺点:1,对cpu资源敏感,默认启动的回收线程数是(cpu数量+3)/4,当cpu数较少的时候,会分掉大部分的cpu去执行收集器线程,影响用户,降低吞吐量。 2,无法处理浮动垃圾,浮动垃圾即在并发清除阶段因为是并发执行,还会产生垃圾,这一部分垃圾即为浮动垃圾,要等下次收集。3,因为使用的是“标记-清除”算法,会产生碎片

6:横跨新生代与老年代的收集器-----G1(Grabage First):基于标记-清理。比较复杂,还不是很懂~


上图中收集器间的连线表示两个收集器能配合使用,一个用于新生代,一个用于老年代。G1则能自己包办两个代~


在代码开发中需要注意:千万不要实例化朝夕朝灭的大对象,比如new byte[1024*1024*20]这样一口气就实例化一个20m的对象,然后用一次后就不需要的。因为老年代中对象回收相对性能比新生代的低,所以这样做会严重影响性能


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

麦田小猪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值