元空间:从jdk1.8开始的叫法,其实就是以前的方法区;但是和方法区也有区别;方法区的数据保存在JVM内存中,元空间的数据保存在物理磁盘上;
.Java文件转换成.class文件,通过类加载子系统 加载到内存中去(方法区),所有的代码都在元空间
内部结构JDK1.8:
采取分代思想,堆中分为年轻代和老年代
年轻代:老年代=1:2;
老年代保存的对象:
1.创建时太大的对象会直接保存到年老代中
2.从年轻代中产生,年代数达到15的对象
年轻代:
Eden区(伊甸园区):新创建的任何对象都在这里
经过GC清理过后仍幸存的对象存在幸存者区
当伊甸园区内存不足时会触发minnor gc,当伊甸园区出发GC之前会通过可达性分析算法得到当前使用的对象,会把使用的对象复制到s区,随机一个,俩个不是同时开启的,进去之后年代数增1,minnor gc会把伊甸园区和另一个s区清空;在运行在产生新对象,以此类推,就是这个迭代循环过程,当s区的年代数达到15时(一般不容易),会把它存放到老年代中,这个对象即将长久存在
年轻代工作原理总结:
新创建的对象会保存在Eden区,当Eden区内存不足时,会触发minnor gc,会对整个年轻代进行回收,再回收之前,会使用可达性分析算法,从栈开始,标记所有正在使用的对象,将使用的对象保存到s0区,然后堆Eden和s1区进行回收,保存到s区的对象年代数会加1.后续若再次Eden内存不足时,将正在使用的对象会存入到另一个s(s1)区,然后对Eden和s0进行回收,当对象的年代数达到15,会移入年老代中
s(suvivor 幸存者)0区:
s(suvivor 幸存者)1区:
伊甸园区:s0:s1=8:1:1
老年代:
老年代中保存到的对象和年代数达到15的对象,当老年代内存不足时,会触发full gc,会堆整个堆内存进行回收,且会造成STW(stop the world),用户会有卡顿体验,若频繁的触发full gc,用户的体验非常差,此时就需要进行JVM优化
注: minor gc和full gc都会出发STW,但是minor gc回收内存小,所以造成的卡顿几乎感觉不到,所以minor gc触发频发频率可以高,但是full gc是对整个堆内存的回收,造成的卡顿用户感觉很明显,所以尽可能的减少full gc 触发;
- mian栈帧:
- int i=1;
- int b=4;
- change(i,b);
- ........
- change()
- int a=1;
- int b=2;
- int c=a+b;
1.尽可能减少大对象的产生
------------操作文件时,尽可能多次操作
2.尽可能让对象在年轻代在年轻代被回收走
-------------尽可能的扩大年轻代的大小
------可以调整Eden和俩个s区的比例
--------调整年轻代和老年代的比例(慎用)
3.更换GMSGC为G1GC
GC的分类:
SerialGC:单线程
ParalleGC: 并发情况下作用的GC
ConcMarkSweepGC:并发情况下作用的GC
------JDK1.5开始默认提供的
G1GC: 从JDK1.9开始默认提供的
G1GC回收机制:
有一个后台线程记录当前回收利用率最高的块,将其作为最优先回收的块,当内存不足时,
对该块进行回收,若回收后够用,则不再继续回收,大大降低STW的时间
注意:每个块在下次使用时作为不同的去使用