前体
让我们先来看一段代码
String s = "a" + "b"
请问这代码产生了几个对象?
有的人可能会说3个
有的人可能会说1个
这里先不说答案,我们先回顾下什么是对象,对象放在哪里?
一般情况下,我们把放在堆里面的称之为对象
也就意味着对象只能放在堆里面
其实并不是这样,对象其实并不是只能放在堆里面
它也能放在栈里面
这里就要讲到第一个概念:
栈上分配
public void test(){
User user = new User();
user....
}
正常情况下
当User对象使用完后,并且之后一段时间内都不再被用到时
对象就会在堆中等待被gc回收
但并不是马上被回收,而是等待一个空间的时间
而gc并不能由我们控制,所以gc的自动回收机制很不是很好
那么这里就有一个疑问?
既然这个对象用完后,就不再被使用
为何要放到堆里面等待被回收呢,何不放在栈里面用完就被弹出去不是很好嘛!
等对象一旦用完,就马上被释放掉 这就是栈上分配的原理
那肯定又有人说既然这个机制这么好,我们都把对象放在栈里不是更好吗?!
其实不见得
这里就要引入第二个概念
逃逸分析
逃逸分析的原理:
就是分析这个对象的引用有没有逃出栈的范围
情景一
public void test(){
User user = new User();
user....
return user;
}
当user使用后,不能马上被回收掉
如果被回收掉了
这是 test 的返回结果要被其他方法进行使用,就会报错
这是对象就绝对不能放在栈内存中,只能放在堆里面
情景二
public void test(User user){
user....
}
上述情况中的user来自更大范围域中,
它的作用域远远大于test
不能在 test 方法结束后,就被回收掉
逃逸分析在分析对象时,会考虑
对象引用要是放在更大的范围中被引用,就绝对不能把对象放在栈里面
但发现对象逃不是栈的范围,就能被放入栈里面
所以对象不仅可以放在堆中,也能放在栈中
前体分析
所以回到我们最早的案例
String s = "a" + "b"
println(s)
答案肯定是
ab
那么到底产生多少对象,我们可以通过字节码进行查看
看到 a 了吗?
看到 b 了吗?
我们只能看到 ab
结论
公式中只产生了一个对象