【虚拟机JVM】堆里面的分区和各自的特点

新生代

新生代又可以进一步划分为一个Eden区和两个Survivor区,Eden是进行内存分配的地方,是一块连续的空闲内存区域,在里面进行内存分配速度非常快,因为不需要进行可用内存块的查找。新对象总是在Eden区中生成,只有经受住了一定的考验后才能顺利的进入到Survivor区中。把Survivor区划分为2块,也是也是为了满足垃圾回收的需要,因为在新生代中经历了回收未必就能进入老年代中。系统总是把对象放在Eden区和一个Survivor区,在垃圾回收时,根据其存活时间被复制到另一个Survivor区或者老年代中,则这之前的Survivor去和Eden区中剩下的都是需要被回收的对象,只对这两个区域进行清除即可,两个Survivor区是交替使用,循环往复,在下一次垃圾回收时,之前被清除的存活区又用来放置存活下来的对象了。一般来说,年轻代区域较小,而且大部分对象是需要进行清除的,采用了"复制算法"进行垃圾回收。

 

老年代

在新生代中经历了N次回收后仍然没有被清除的对象,就会被放到老年代中,都是生命周期较长的对象。对于老年代和永久代,采用标记-整理的算法。标记的过程是找出当前还存活对对象,并进行标记;清除则是遍历整个老年区,找已经标记的对象并进行清除,然后把存活的对象移动到整个内存区的一端,使得另一端是一块连续的空间,方便进行内存分配和复制。

1)Minor GC:当新对象生成,但在Eden申请空间失败时就会触发,对Eden进行GC,清除掉非存活的对象,并且把存活的对象移动到Survivor区中的其中一块。前面提到的考验就是Minor GC,也就是说对象经过了Minor GC才能够进入到存活区中。这种形式的GC只会在新生代中进行,因为大部分对象都是从Eden区开始的,同时Eden不会分配的太大,所以对Eden区的GC会非常地频繁。

2)Full GC:对整个堆进行整理,包括了新生代老年代和永久代。Full GC要对整个块进行回收,所以要比Minor GC慢很多,因此应该尽可能的减少Full GC的次数。

 

Minor GC与FullGC分别什么时候发生?

如果Eden空间满了,会触发Minor GC。Minor GC后仍然存活的对象会被复制到S0中去。这样Eden就被清空可以分配给新的对象。又触发了一次Minor GC,S0和Eden中存活的对象被复制到S1中,并且S0和Eden被清空。在同一时刻只有Eden和一个Survivor区同时被操作。当每次对象从Eden复制到Survivor或者从Survivor中的一个复制到另外一个,有一个计数器会自动增加值。默认情况下,如果复制发生超过16次,JVM机会停止复制并把他们移动到老年代中去。

如果一个对象不能在Eden中创建,它会直接被创建在老年代中。如果老年代的空间被占满会触发老年代的GC,也被称为Full GC。Full GC是一个压缩处理过程,所以很慢。

 

如何减少GC出现的次数

1)对象不用时最好显示置为Null

一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显示地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

2)尽量少用System.gc()

此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

3)尽量少用静态变量

静态变量属于全局变量,不会被GC回收,他们会一直占用内存。

4)尽量使用StringBuffer,而不用String类累加字符串

由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如str5 = str1 + str2 + str3 + str4,这条语句执行过程中会产生多个垃圾对象,因为对 + 操作时都必须创建新的String对象,但这些过度对象对系统来说是没有意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有的基础上进行扩展,不会产生中间对象。

5)分散对象创建或删除的时间

集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。

集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲时间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。

6)尽量少用finalize函数。因为它会加大GC的工作量,因此尽量少用finalize方式回收资源。

7)如果需要使用经常用到的图片,可以使用软引用类型,他可以尽可能将图片保存到内存中,供程序调用,而不引起OOM

8)能用基本类型如int、long,就不用Integer、Long对象

基本类型变量占用的内存资源比包装类对象占用的少得多,如果没有必要,最好使用基本变量。

9)增大-Xmx的值。

数组多大放在JVM老年代?永久代对象如何GC?如果想不被GC怎么办?如果想在GC中生存一次怎么办?

虚拟机提供了一个-XX:PretenureSizeThreshold参数(通常是3MB),令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制。(新生代采用复制算法收集内存)

垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完成垃圾回收(Full GC)。如果仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。

让对象实现finalize()方法,一次对象的自我拯救。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值