一个进程对应一个JVM实例,一个JVM只有一个运行时数据区,里面只有一个方法区和一个堆,所有线程共享一个方法区和一个堆,但是每一个线程都由一套本地方法栈,栈,程序计数器
所有的线程都共享堆,并发性差,因此有一个线程私有的缓冲区Thread Loacal Allocation Buffer, TLAB,提高并发性。
虚拟机栈没有GC,由OOM,栈溢出
程序计数器没有error 没有GC
本地方法栈有栈溢出
堆有OOM GC是GC发生的重点区域
方法区有OOM 有GC但不多。
堆内存:
xms——堆初始内存 默认为物理机内存的1/64
xmm——堆最大内存 默认为物理机内存的1/4
调节堆大小为20M
![]()
年轻代(伊甸园区 加幸存者1、2区)+老年代 = 20M
堆内存的大小等于年轻代加老年代,不包括元空间。
堆内存分区:
新生代(伊甸园区 幸存者一区 幸存者二区) 老年代 永久区 (虚拟机内存) 1.7
新生代 (伊甸园区 幸存者一区 幸存者二区) 老年代 元空间(物理机内存)1.8
新生区=新生代=年轻代 养老区=老年区=老年代
年轻代:
存放朝生夕死,声明周期短创建和消亡都非常迅速的对象
拉年区:
放生命周期长的对象
年轻到细分为 伊甸园区 幸存者1区 幸存者2区 1 2区也叫from to区 (gc后空的区域就是to区)
伊甸园区:幸存者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后可以晋升到老年区。
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在伊甸园区。