JVM-堆
1. 堆的作用
- 堆的作用其实就是保存运行时的数据,主要就是存储创建的对象;但是在不同版本的JDK有些许的变化,在JDK8以后堆中还存储了静态变量和字符串常量池
2.堆的内存细分
- 新生代
- Eden
- Survivor
- from
- to
- 老年代
3. 参数调整
-
-Xms
- 默认值为电脑的1/64
-
-Xmx
- 默认值为电脑最大内存1/4
-
注意
- 为什么设置的堆大小是600M而使用Runtime对象去获取时发现总的可用大小为575M;这里是因为Survivor区在划分时s0和s1只有一个存储数据
-
如何查看当前内存使用情况
- 设置参数:-XX:+printGCDetails
- 使用命令
- jps查看进程id
- jstat -gc 进程id 查看使用情况
- jvisulvm命令可视化查看
4.新生代比例
- -XX:NewRatio=2,表示新生代占1老年代占2,新生代占整个堆的1/3
- -Xmn:设置新生代的大小
- 查看设置的值
- jinfo -flag 参数名【如:NewRatio】 进程id
- Eden & Survivor的比例
- 默认:8:1:1
- 设置:-XX:SurvivorRatio
- 注意:
- 默认虽然是8:1:1 但是并不是真的这样分配,因为有一个自适应机制存在;可以通过参数: -XX:-UseAdaptiveSizePolicy关闭这个自适应机制
5.GC何时触发
- 当Eden区满了的时候,触发YGC/MinorGC; 并且每个对象没经过一次GC年龄值加1;到达一定的值以后进入老年代,可以自行设置,参数名:-XX:MaxTenuringThreshold, 默认值是15
- Survivor区的GC是被动跟着Eden区的,如果Survivor满了直接将对象放入永久代
- 如果老年代放不下了,则触发majorGC
6.TLAB(Thread Local Allocation Buffer)
- 因为默认情况下多个线程在创建对象时都是在操作Eden区, 那么这种情况加锁解决线程安全问题会导致性能下降; 解决方式就是在Eden区划分更小的内存单位给每一个线程,这就是TLAB;此处也证明了堆空间有部分内存是线程私有的
7. 逃逸分析
- 逃逸分析默认只能在server模式下生效
- 当一个对象在方法中被定义之后,对象只在方法内部使用则认为没有发生逃逸; 没有发生逃逸则可以将对象分配在栈上
8.对象只能在堆中创建?
- 根据逃逸分析可以知道,如果一个对象的使用没有超出方法,该对象可以在栈上分配,并且当方法调用完成后直接在栈帧出栈式回收内存