一.简述
什么是堆?或者堆的特点?
- 堆是JVM在运行时管理的最大的一块物理上不连续但在逻辑上连续的内存空间。
- JVM在运行过程中产生的数组和对象实例都存放在堆中,通过栈引用。
- 在栈中的方法执行完毕(弹栈)使得引用失效的时候的时候,堆中的所指向的数据并不会马上删除,而是等待GC回收。
- 启动时可通过配置JVM启动参数 -Xms(堆开始内存大小) -Xmx(堆最大内存大小)确定大小,也可通过JDK自带工具jvisualvm的visualGC插件查看堆的内存具体分布。
二.堆的JvmGC分代模式下的逻辑组成
新生代:
eden(伊甸园区),s0(幸存者区,from区或者to区),s1(幸存者区,from区或者to区)【默认内存大小比列 8:1:1】
老生代
三.堆的GC的回收过程
1. JDK8中的GC方式
Jdk8 默认垃圾收集器Parallel Scavenge(新生代【标记-复制算法】)+Parallel Old(老年代【标记整理算法】)
2. 新生代的GC方式
-
第一次GC:几乎所有的对象和数组都会在伊甸园区被创建,等到对象占满的时候触发第一次GC。回收器将不能回收的对象放入S0区,并且记录年龄age+1。
-
第二次GC: 将伊甸园区和S0区的不能回收的对象放入S1区,清空伊甸园区和S0区,并且记录年龄。
-
第n次GC: 将龄超过15的对象,放入老生代。
3.老生代的GC方式
- 由于大多数的对象的生命周期是朝生夕死的,所以一般采用标记复制算法,但是标记算法更适合生命周期长一些的老生代。
- 不同Jdk版本有不同的垃圾回收器,不同的垃圾回收器又会选择不同的算法。 参考算法章节
4. GC的触发机制
针对新生代的回收叫MinorGC也叫youngGC,当伊甸园区满的时候触发,一般回收比较快,会触发STW。
针对老生代的回收叫FullGC也叫MajorGC, MajorGC比MinorGC慢10倍以上,如果MajorGC后还是空间不足那就会报OOM。
- 当老生代空间不足的时候触发。
- 手动调用System.gc()的时候触发。
- 一般FullGC触发的时候会先触发一次MinorGC,MinorGC会再对幸存者区进行一次回收,如果需要放入老生代的对象还是大于剩余的剩余空间,再进行一次触发。
- 方法区空间不足的时候。
四.逃逸分析
逃逸分析是一种有效的降低Java同步负载和内存分配压力的机制。 Jvm能根据新对象的引用范围判断是否要将分配进堆内存。
- 方法逃逸: 在一个方法内的局部变量,如果存在调用其他方法时将其传入,或者作为返回值直接返回,我们称之为方法逃逸。
- 线程逃逸:当前对象除了被自身的线程外还被其他线程访问修改,叫做线程逃逸。
逃逸分析的好处:
- 栈上分配:如果没有发生逃逸,Jvm会将对象分配到栈上面,随这方法执行完之后弹栈,对象不用分配到堆上面,也不用GC,提高效率。
- 锁消除: 当方法内的锁有且只能被同一个线程访问,JVM会自动优化锁消除,提高执行效率。