JVM学习初级篇(三)Java堆

目录

堆的组成 

Young区演变过程

新生代组成

GC流程

Full GC

悲观策略

常规策略

堆内存诊断


堆的组成 

 通过new关键字创建的对象都会使用堆。

堆是线程共享区域,由于共享所以要考虑线程安全

有垃圾回收机制

Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。
在 Java 中,堆被划分成两个不同的区域:新生代 ( Young )、老年代 ( Old )。新生代 ( Young ) 又被划分为三个区域:Eden、
From Survivor、To Survivor。 
这样划分的目的是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

堆内存模型:堆大小 = 新生代 + 老年代。其中,堆的大小可以通过参数 –Xms、-Xmx 来指定

Young区演变过程

 1. 如果堆只划分2个大整体:Young区和 Old区 ,如下图

  

2. 过了一段时间young区进行了垃圾回收,引起了空间内存的不连续性,产生了随便,这时候新创建的对象可能因为占用太大,而无法存放,如下图

3.这时候就可以把young区划分为Eden区和 Survivor区。发生垃圾回收时,可以先把Eden存活的对象整理后存放在Survivor区,如下图。下Eden区就有空间存放新对象

 4.如果在发生垃圾回收,Survivor区也会产生不连续空间,如下图

5.这个时候Eden区存活的对象就无法放在Survivor区。这个时候就想起了这种问题之前的解决办法是在划分一个空间出来。这就把Survivor区分成from区和to区,如下图,这样就解决了survivor区垃圾回收后空间不连续问题。

Survivor的划分的两个区大小理论上一样大小的。如果不一样,就会发生如果T0区的存活的对象>T1空间大小,那T0区的对象就无法移动过去。如下图

新生代组成

新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 )。

新生代被细分为Eden(伊甸园)和两个Survivor(幸存区)。

默认的,Edem : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定 ),即: Eden = 8/10 的新生代空间大小,from =
to = 1/10 的新生代空间大小。 

JVM 每次只会使用 Eden 和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块 Survivor 区域是空闲着
的。 因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。

GC流程

Java 中的堆也是 GC 收集垃圾的主要区域。GC 分为两种:Minor GC、Full GC ( 或称为 Major GC )。新生代几乎是所有 Java 对象出生的地方,即 Java 对象申请的内存以及存放都是在这个地方,新生代是 GC 收集垃圾的频繁区域。

对象分配和GC的流程图如下

 进入老年代的情况;

1.对象年龄达到存活的阈值

 当对象在经过一次 Minor GC 后,如果对象还存活,并且能够被另外一块 Survivor 区域所容纳,则使用复制算法将这些仍然还存活的对象复制到另外一块 Survivor 区域 ( 空闲的区,即 to 区域 ) 中,然后清理所使用过的 Eden 以及 Survivor 区域 (使用了的区, 即 from 区域 ),并且将这些对象的年龄设置为1,以后对象在 Survivor 区每熬过一次Minor GC,就将对象的年龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定 ),这些对象就会成为老年代。

2. Survivor一半的空间都被同年龄对象占用了,则>=该年龄的对象可以直接进入老年代

为了能够更好的适应不同的程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代。如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接
进入老年代。例如新生代教室10个座位,有5个座位都让18岁的占了,那大于等于18岁的同学都经历过多次YGC的淘汰,所以他们都可以进入老年代教室。

3.MinorGC时,to区已经无法装下Eden区和from区存活对象时,将它们放入老年代

4.大对象进入老年代

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

Full GC 是发生在老年代的垃圾收集动作,所采用的是“标记-清除”或者“标记-整理”算法。
       堆内存中的老年代(Old)都是“老不死”,里面的对象几乎个个都是在 Survivor 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。因此,Full GC 发生的次数不会有 Minor GC 那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长。

Full GC

老年代的Full GC 并不会一定等到空间不足,或者满了才会进行GC。

悲观策略

  •  发生MinorGC之前,JVM会检查老年代的最大可用的连续空间是否放的下新生代过来的对象,大家想一想,老年代都没位置放不下了,你还跑过来干什么:

1.如果放得下,那么MinorGC可以确保是安全的。

2.如果放不下,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试这进行一次MinorGC,尽管这次MinorGC是有风险的;如果小于,或者HandlePromptionFailure设置不允许冒险,那这是也要改为进行一次FullGC.。

  • MinorGC之后,Survivor存活的对象大小>老年代的大小,那就直接Full GC

另外,标记-清除算法收集垃圾的时候会产生许多的内存碎片 ( 即不连续的内存空间 ),此后需要为较大的对象分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。

常规策略

  • 元空间不足

堆内存诊断

 jps查看进程

jmap -heap 进程id

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值