JVM内存结构

程序计数器Program Counter Register,也叫寄存器

  • 作用:记住下一条jvm指令的执行地址
  • 特点
    • 是线程私有的
    • 不在存在内存溢出

虚拟机栈Java Virtual Machine Stacks

  • 是每个线程运行所需要的内存空间
  • 每个栈由多个栈桢(Frame,即调用的每个方法)组成,对应着每次方法调用时所占用的内存,保存着方法的参数、局部变量,返回值
  • 每个线程只能有一个活动栈桢,对应着当前正在执行的那个方法
问题辨析
  1. 垃圾回收涉及栈内存吗?
    不涉及,因为栈桢在执行完成后就出栈了,不需要手动回收
  2. 栈内存分配越大越好吗?
    不是,一个栈对应一个线程运行所需要的空间,物理内存大小是固定的,所以栈内存越小,可运行线程数越多;栈内存越大,可运行线程数越少。所以栈内存不是分配的越大越好。
  3. 方法内的局部变量是否线程安全?
  • 如果方法内的局部变量没有逃离方法的作用范围,那么它是线程安全的
//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 栈桢过大,即一个栈桢就充满了整个栈,一般这种情况见不到,因为一个栈桢中就存储一个方法中的相关参数,用不了那么大的内存

未完待续...

posted @ 2023-03-08 08:44  程长新  阅读(13)  评论(0编辑  收藏  举报