大部分new出来的对象被分配在堆上,而不是全部。
-
通过对Java对象分配的过程分析,可以知道有另外两个地方也是可以存放对象的。
-
这两个地方分别栈 (涉及逃逸分析相关知识)和TLAB(Thread Local Allocation Buffer)。
栈上分配
- 如果确定一个对象的作用域不会逃逸出方法之外,
- 那可以将这个对象分配在栈上,
- 这样,对象所占用的内存空间就可以随栈帧出栈而销毁。
- 在一般应用中,不会逃逸的局部对象所占的比例很大,
- 如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁了,
- 无须通过垃圾收集器回收,可以减小垃圾收集器的负载。
- JVM允许将线程私有的对象打散分配在栈上,而不是分配在堆上。
- 分配在栈上的好处是可以在函数调用结束后自行销毁,
- 而不需要垃圾回收器的介入,从而提高系统性能。
- 栈上分配的技术基础:
-
一是逃逸分析:
-
逃逸分析的目的是判断对象的作用域是否有可能逃逸出函数体。
-
-
二是标量替换:允许将对象打散分配在栈上,
-
比如若一个对象拥有两个字段,会将这两个字段视作局部变量进行分配。
-
-
只能在server模式下才能启用逃逸分析,
-
参数-XX:DoEscapeAnalysis启用逃逸分析,
-
参数-XX:+EliminateAllocations开启标量替换(默认打开)。
-
Java SE 6u23版本之后,HotSpot中默认就开启了逃逸分析,
-
可以通过选项-XX:+PrintEscapeAnalysis查看逃逸分析的筛选结果。
-
-
-
TLAB
- TLAB的全称是Thread Local Allocation Buffer,
- 即线程本地分配缓存区,
- 这是一个线程专用的内存分配区域。
- JVM使用TLAB来避免多线程冲突,
- 在给对象分配内存时,每个线程使用自己的TLAB,
- 这样可以避免线程同步,提高了对象分配的效率。
- TLAB本身占用eEden区空间,
- 在开启TLAB的情况下,虚拟机会为每个Java线程分配一块TLAB空间。
- 参数-XX:+UseTLAB开启TLAB,默认是开启的。
- TLAB空间的内存非常小,
- 缺省情况下仅占有整个Eden空间的1%,
- 当然可以通过选项-XX:TLABWasteTargetPercent设置TLAB空间所占用Eden空间的百分比大小。
- 在开启TLAB的情况下,虚拟机会为每个Java线程分配一块TLAB空间。
- 由于TLAB空间一般不会很大,
- 因此大对象无法在TLAB上进行分配,总是会直接分配在堆上。