【jvm学习02】虚拟机栈

文章目录

      • 1.栈的数据结构
      • 2.栈的相关定义与演示
      • 3.问题辨析
      • 4.栈内存溢出
      • 5.线程运行诊断

1.栈的数据结构

【jvm学习02】虚拟机栈_第1张图片

2.栈的相关定义与演示

  • 每个线程运行时所需要的内存,称为虚拟机栈
  • 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
    【jvm学习02】虚拟机栈_第2张图片
    【jvm学习02】虚拟机栈_第3张图片
    【jvm学习02】虚拟机栈_第4张图片
    【jvm学习02】虚拟机栈_第5张图片
    【jvm学习02】虚拟机栈_第6张图片

3.问题辨析

  • 垃圾回收是否涉及栈内存?
    不会,因为栈内存就是方法调用产生的栈帧内存,而栈帧内存在方法调用结束后都会被弹出栈,也就是说自动的释放内存回收掉,因此不需要垃圾回收。
  • 栈内存分配越大越好吗?
    不是,物理内存是一定的,如果栈内存越大,那么线程数越少。一般采用系统默认的占内存大小就可以了。
  • 方法内的局部变量是否线程安全?
    如果方法内局部变量没有逃离方法的作用范围,他就是线程安全的
    如果是局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全问题。
//局部变量的线程安全问题
public class Demo2 implements Runnable {
    //多个线程同时调用这个方法
    @Override
    public void run() {
        int x=0;
        for(int i=0;i<50;i++){
            x++;
            System.out.println(x);
        }
    }
    public static void main(String[] args) {
        Thread t1 = new Thread(new Demo2());
        t1.start();
        Thread t2 = new Thread(new Demo2());
        t2.start();
    }
}

【jvm学习02】虚拟机栈_第7张图片

public class Demo3 {
    public static void m1(){
        //局部变量一直在方法内,是线程安全的
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    public static void m2(StringBuilder sb){
        //由于sb可能是一个共享数据,因此需要考虑线程安全问题
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }

    public StringBuilder  m3(){
        //sb作为变量返回,有可能是共享数据,需要考虑线程安全问题
        StringBuilder sb = new StringBuilder();
        sb.append(1);
        sb.append(2);
        sb.append(3);
        return sb;
    }

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        sb.append(4);
        sb.append(5);
        sb.append(6);
        new Thread(()->{m2(sb);});
    }
}

4.栈内存溢出

  • 栈帧过多会导致栈内存溢出
  • 栈帧过大会导致栈内存溢出

递归调用没有设置终止条件导致栈内存溢出:

public class Demo4 {
    private static int count;
    public static void main(String[] args) {
        try {
            method1();
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(count);
        }
    }

    private static void method1() {
        count++;
        method1();
    }
}

在这里插入图片描述

5.线程运行诊断

你可能感兴趣的:(Java虚拟机)