内存分配图
对象栈上分配
JAVA中的对象都是在堆上进行分配的,当对象没有被引用时,需要进行CG进行回收内存,但是在对象数量非常多的时候,会进行对GC造成非常大的压力(频繁的进行GC,并且清理的对象数多),影响了应用的性能。在此基础上JVM针对性的进行优化,
JVM通过逃逸分析来确定对象不会被外部访问,从而判断该对象可以在栈上分配内存,这样该对象所占用的内存空间就可以随着栈的销毁而销毁,减轻了垃圾回收的压力(GC)
对象逃逸分析:分析对象的动态作用域。
-
当对象在方法中定义后,被外部方法引用
public Heiheihei test(){ Heiheihei hei =new Heiheihei(); hei.setName("伞兵") //其他操作 return hei; }
该对象被返回,所以该对象的作用域范围不确定。无法判断是否被外部方法所引用。
-
当对象定义后,不被外部方法引用
public void test(){ Heiheihei hei =new Heiheihei(); hei.setName("伞兵") //其他操作 }
该对象没有被返回,可以确定没有被外部方法所引用。可以分配栈空间(内存)中,该对象随着栈内存一起被回收销毁。
这种情况下可以通过参数
-XX:+DoEscapeAnalysis
来开启逃逸分析,通过标量替换优先分配栈上(栈上分配)注意:JDK7后默认开启逃逸分析,关闭参数为
-XX:-DoEscapeAnalysis
标量替换
进行逃逸分析确定对象不会被外部访问,对象被进一步分解,JVM不会创建该对象,而是将该对象的成员变量分解成若干个被这个方法使用的成员变量进行替换,而这些替换的成员变量将会在栈帧或寄存器上分配空间,这样不会因为没有连续空间存储大对象而造成内存不够分配。
- 开启标量替换:
-XX:+EliminateAllocations
,JDK7后默认开启
栈上分配依赖于逃逸分析和标量替换
对象在Eden区分配
绝大多少情况下,对象都在新生代的Eden区分配。而当Eden区没有空间进行分配时,JVM虚拟机将发起一次Minor GC。
补充
- Minor GC/Young GC
发生在新生代的垃圾回收 ,Minor GC非常频繁,回收速度比较块。
- Major GC/Full GC
发生在年轻代,老年代,方法区的垃圾回收,一般比 Minor GC慢10倍以上
过程
- 大量的对象被分配到Eden区,当Eden区满了后触发minor gc ,大部分的对象成为垃圾被回收,剩余对象将会挪到空的Survivor区(幸存者一或二区),下一次Eden区满后将再次触发minor GC,将Eden区和survivor区的对象进行回收,存活对象挪动到另一块为空的Survivor区(幸存者一或二区)
- 由于新生代对象存活下来对象非常少,存活时间短,所以JVM默认Eden:Survivor1:Survivor2比例为8:1:1 ,调节方面
Eden区尽量的大,Survivor区够用即可
.
JVM默认参数
-XX:+UseAdaptiveSizePolicy
(默认开启),会导致这个8:1:1比例自动变化,不想这个比例有变 化可以设置参数-XX:-UseAdaptiveSizePolicy