JVM基础篇-虚拟机栈
定义
Java Virtual Machine Stacks (Java 虚拟机栈)
- 每个线程运行时所需要的内存,称为虚拟机栈
- 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
- 每个线程只能有一个活动栈帧,对应着当前
正在执行
的那个方法
栈帧组成部分:方法参数、局部变量、返回地址
执行流程
方法执行时执行压栈操作,如果该方法调用了其他方法,其他方法被调用时执行压栈操作,方法执行完成后执行出栈操作
问题辨析
垃圾回收是否涉及栈内存?
答:不涉及,当方法执行完成后会执行出栈操作,对应的栈内存会被自动释放
栈内存分配越大越好吗?
答:不是,栈内存的越大只会使得方法递归调用的次数增大,但是如果栈内存越大,则意味着每个线程占用的内存越大,而可同时运行的线程数则会变少
📌指定栈内存大小
-Xss:
- 如果不设置,在Linux/MacOS中默认为1024KB,Windows系统则依赖于虚拟内存的大小
方法内的局部变量是否线程安全?
- 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
- 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全,如果方法参数或返回值为基本类型,则依然线程安全
package com.vmware.stack;
public class Demo1 {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
sb.append(1);
sb.append(2);
sb.append(3);
new Thread(() -> {
m2(sb);
}).start();
}
/**
* @apiNote 该方法中StringBuild线程安全,因为外部无法方法
*/
public static void m1() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(1);
stringBuilder.append(2);
stringBuilder.append(3);
System.out.println(stringBuilder.toString());
}
/**
* @param builder
* @apiNote 该方法线程不安全,因为StringBuild可能有其他线程访问
*/
public static void m2(StringBuilder builder) {
builder.append(1);
builder.append(2);
builder.append(3);
System.out.println(builder.toString());
}
/**
* @apiNote 该方法线程不安全,可能有其他线程访问返回值进行修改
* @return
*/
public static StringBuilder m3() {
StringBuilder builder = new StringBuilder();
builder.append(1);
builder.append(2);
builder.append(3);
return builder;
}
}
栈内存溢出
- 栈帧过多导致栈内存溢出
- 方法递归调用
- 部分第三方类库溢出,例如json序列化循环依赖
- 栈帧过大导致栈内存溢出