前言:new出来的对象一定是储存在堆中的吗?
1. JIT简介
- JIT 是 just in time 的缩写, 也就是即时编译编译器。使用即时编译器技术,能够加速 Java 程序的执行速度。
- 首先,我们大家都知道,通常通过 javac 将程序源代码编译,转换成 java 字节码,JVM 通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译。很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢很多。为了提高执行速度,引入了 JIT 技术。
- 在运行时 JIT 会把翻译过的机器码保存起来,以备下次使用,因此从理论上来说,采用该 JIT 技术可以接近以前纯编译技术。
- 代码在执行过程中,JIT会为我们做很多优化,其中有一种技术叫做逃逸分析。
2. 逃逸分析
当一个对象被定义之后,可能会被外部对象引用,称之为方法逃逸;也有可能被其他线程所引用,称之为线程逃逸。
回归到我们的主题对象是一定会被分配到堆中的吗?
public class Stack {
public static void main(String[] args) throws InterruptedException {
Stack stack = new Stack();
for (int i = 0; i < 1000000; i++) {
stack.add();
}
Thread.sleep(Long.MAX_VALUE);
}
public void add() {
Student student = new Student();
}
}
上面这段代码就是不停的调用add()方法生成一个Student对象。该方法创建Student对象没有被外界所引用,则会被我们的JIT的逃逸分析所优化来减轻我们不停创建对象导致堆内存压力过大,会将我们的部分对象分配到栈帧中,在执行完方法后出栈销毁。
验证如下(从JDK7开始默认是开启逃逸分析的)
num #instances #bytes class name
----------------------------------------------
1: 6470 4002904 [B
2: 17305 3255472 [C
3: 100087 1601392 Student
我们可以看到Student的在堆内存中只有100087对象实例。
现在我们来关闭逃逸分析 -XX:-DoEscapeAnalysis
num #instances #bytes class name
----------------------------------------------
1: 1000000 16000000 Student
2: 6470 4002952 [B
3: 17307 3255864 [C
当我们关闭了逃逸分析之后可以看到堆内存中存在1000000个Student对象实例。
希望大家知道创建的对象不一定都是存放在堆内存中的。
如何用idea查看堆内存实例数量。
@一名互联网的吊车尾