JVM内存结构
程序计数器Program Counter Register,也叫寄存器
- 作用:记住下一条jvm指令的执行地址
- 特点
- 是线程私有的
- 不在存在内存溢出
虚拟机栈Java Virtual Machine Stacks
- 是每个线程运行所需要的内存空间
- 每个栈由多个栈桢(Frame,即调用的每个方法)组成,对应着每次方法调用时所占用的内存,保存着方法的参数、局部变量,返回值
- 每个线程只能有一个活动栈桢,对应着当前正在执行的那个方法
问题辨析
- 垃圾回收涉及栈内存吗?
不涉及,因为栈桢在执行完成后就出栈了,不需要手动回收 - 栈内存分配越大越好吗?
不是,一个栈对应一个线程运行所需要的空间,物理内存大小是固定的,所以栈内存越小,可运行线程数越多;栈内存越大,可运行线程数越少。所以栈内存不是分配的越大越好。 - 方法内的局部变量是否线程安全?
- 如果方法内的局部变量没有逃离方法的作用范围,那么它是线程安全的
//s1的声明方式是线程安全的
public static void method1(){
//StringBuffer:线程不安全的
StringBuffer s1 = new StringBuffer();
s1.append("A");
s1.append("B");
...
}
- 如果局部变量引用了对象,并逃离了方法的作用范围,那么需要考虑线程安全
//先说结论,这个是线程不安全的
//StringBuilder是线程不安全的
public static void method2(StringBuiler sBuilder){
sBuilder.append("A");
sBuilder.append("B");
...
}
//我们在main操作一下
public static void main(String[] args){
StringBuilder s = new StringBuilder();
new Thread(()->{
s.append("a");
s.append("b");
}).start();
method2(s);
}
它们会抢s的资源,是线程不安全的。严格的来说sBuilder不是方法内的局部变量,它是形参的局部变量,形参也会存在局部变量表中
//结论:不是线程安全的(有可能存在问题)
public static StringBuilder method3(){
StringBuilder s1 = new StringBuilder();
s1.append("A");
s1.append("B");
...
return s1;
}
这次不传参数,而是返回。引用类型一返回出去可能被其他位置上的多个线程所调用
栈内存溢出的情况
1 栈桢过多,比如递归调用且程序没有出口
2 栈桢过大,即一个栈桢就充满了整个栈,一般这种情况见不到,因为一个栈桢中就存储一个方法中的相关参数,用不了那么大的内存
未完待续...