本篇文章总结虚拟机栈的面试题!!
《Java 虚拟机规范》中描述了两种异常:
注意:栈容量只能由 -Xss 参数来设定
不能!!通过调整栈容量,可能会使原本出现溢出的代码不出现溢出了;但无法保证所有情况都不出现溢出!!
假设原本栈容量可以支持 5000 次调用,但代码有 6000 次调用,就会出现溢出;此时调整栈容量保证其可以支持 7000 次调用,那么原来的代码就不会出现溢出了
但如果另外一个代码有 8000 次调用,依旧会出现溢出!!
不一定!!分配越大的栈容量,会压缩其他部分的大小,比如:堆,方法区等
这里总结一下「运行时数据区域」的各个部分是否会发生 Error 或者 GC!!
Error | GC | |
---|---|---|
方法区 | ✅ | ✅ |
堆 | ✅ | ✅ |
虚拟机栈 | ✅ | ❌ |
本地方法栈 | ✅ | ❌ |
程序计数器 (PC) | ❌ | ❌ |
需要分情况讨论,有的情况是线程安全,有的情况是线程不安全,会发生对象逃逸
// 情况一:线程安全
// 对象 s1 随着方法调用的结束而消亡,不会被多个线程共享
public static void f1() {
// 注意:StringBuilder 不是线程安全;StringBuffer 是线程安全
StringBuilder s1 = new StringBuilder();
s1.append("a");
s1.append("b");
}
// 情况二:线程不安全
// 对象 s1 不会随着方法调用的结束而消亡,因为随着方法的返回值逃逸出去了,可能会被多个线程共享
public static StringBuilder f2() {
StringBuilder s1 = new StringBuilder();
s1.append("a");
s1.append("b");
return s1;
}
// 情况三:线程不安全
// 对象 s1 随着方法的参数传入方法中,不是线程私有,可能会被多个线程共享
public static void f3(StringBuilder s1) {
s1.append("a");
s1.append("b");
}
// 情况四:线程安全
// 对象 s1 随着方法调用的结束而消亡,不会被多个线程共享;而返回值是 String,它是不可变的
public static String f4() {
StringBuilder s1 = new StringBuilder();
s1.append("a");
s1.append("b");
return s1.toString();
}