JVM---Heap堆

JVM---Heap堆_第1张图片

 

一个进程对应一个JVM实例,一个JVM只有一个运行时数据区,里面只有一个方法区和一个堆,所有线程共享一个方法区和一个堆,但是每一个线程都由一套本地方法栈,栈,程序计数器

所有的线程都共享堆,并发性差,因此有一个线程私有的缓冲区Thread Loacal Allocation Buffer, TLAB,提高并发性。

 虚拟机栈没有GC,由OOM,栈溢出

程序计数器没有error 没有GC

本地方法栈有栈溢出

堆有OOM GC是GC发生的重点区域

方法区有OOM 有GC但不多。

堆内存:

xms——堆初始内存    默认为物理机内存的1/64

xmm——堆最大内存  默认为物理机内存的1/4

调节堆大小为20M 

 JVM---Heap堆_第2张图片

 年轻代(伊甸园区 加幸存者1、2区)+老年代 = 20M

堆内存的大小等于年轻代加老年代,不包括元空间。

JVM---Heap堆_第3张图片

堆内存分区:

新生代(伊甸园区 幸存者一区  幸存者二区)    老年代     永久区 (虚拟机内存)  1.7

新生代 (伊甸园区  幸存者一区  幸存者二区) 老年代  元空间(物理机内存)1.8 

新生区=新生代=年轻代   养老区=老年区=老年代

年轻代:

存放朝生夕死,声明周期短创建和消亡都非常迅速的对象

拉年区:

放生命周期长的对象 

年轻到细分为  伊甸园区  幸存者1区 幸存者2区  1 2区也叫from to区 (gc后空的区域就是to区)

JVM---Heap堆_第4张图片

伊甸园区:幸存者1区:幸存者2区 = 8 : 1 : 1

年轻代:老年代 = 1 : 2

IBM研究80%的对象都是生命周期短的,绝大部分对象在新生区就销毁了!!!

绝大多数对象都是伊甸园区new出来的,但是也有例外,如果对象超出伊甸园区大小,就直接在老年区new出来了!!!!!

对象没过一次GC就会增长一次年龄,年龄超过15就可以进入养老区。

 

 图解GC过程

年轻代GC:

1.伊甸园区不断new对象 伊甸园区满了,发生YGC,将伊甸园区和from区存活对象复制到to区,然后清理伊甸园区和from区。只有伊甸园区满了才会触发YGC,from区满了不会触发GC。经过一次GC后还存活的对象年龄加1,年龄到15后可以晋升到老年区。

JVM---Heap堆_第5张图片

2.伊甸园区满了发生YGC,绿色对象存活将复制到s1并且年龄加1,伊甸园区和 s0清空。

老年区GC:

老年代满了后触发OGC,OGC后发现对象仍然无法保存,就会OOM

总结:

1.s0 s1 一次GC后谁是空的谁就是to区

2.伊甸园区满了才会触发YGC,s1 s0 满了不会触发YGC

3.GC经常发生在新生区,很少发生在老年区,几乎不发生在元空间。

4.元空间是方法区的落地实现

YoungGC OldGC FullGC 

GC会发生STW stop the world,OldGC STW 的时间是YoungGC的10倍。频繁的GC会停掉用户线程,体验不好。

部分收集:YoungGC OldGC

整堆手机:FullGC

年轻代YoungGC触发机制:

1.伊甸园区满了就触发YoungGC,幸存者区满了不会触发YoungGC

2.YoungGC非常频繁因为java大部分对象生命周期都很短,YoungGC对用户线程影响小,YoungGC速度很快,影响大的是OldGC

老年代触发机制:

1.老年代空间不足了就会先触发YoungGC,如果YoungGC后仍然不足,就会发生FullGC

也就是说OldGC之前至少有一次YoungGC

2.OldGC时间更长STW时间更长,OldGC后如果空间仍然不足,就会OOM

 堆分代思想:

堆空间分代的唯一理由就是优化GC

因为java大部分对象都是临时对象生命周期短,需要及时清理腾出空间 ,回收速度也很快,这就是分出年轻代的理由。

对于生命周期长的对象,放在老年代为了减少GC。

堆空间都是线程共享的吗?

不是 存在线程私有的缓冲区 Thread Local Allocation Buffer  TLAB

线程共享堆,并发性差,为了缓解这样的问题,就有了TLAB线程私有的缓冲区 ,线程对象先new在缓冲区tlab,放不下再new在伊甸园区。

 

 

你可能感兴趣的:(jvm,java)