JVM-03虚拟机栈

30 阅读2分钟

虚拟机栈

image.png

回忆栈的数据结构

image.png

image.png

调用第一个方法时,会为其分配一个栈帧空间,并且把其压入栈内,当方法执行完时,就会释放栈帧空间

image.png

定义

  • 每个线程运行时所需要的内存,称为虚拟机栈
  • 每个栈由多个栈帧组成,对应者每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
/**
  * 演示栈帧
 **/
 public class Demo1_1 {
     public static void main(String[] args){
         method1();
     }
     private static void method1(){
         method2(1,2);
     }
     private static int method2(int a, int b){
         int c = a + b;
         return c;
     }
 }

问题辨析

  1. 垃圾回收是否涉及栈内存?

    不设计,栈帧内存在每次方法调用结束后,都会自动释放,根本不需要垃圾回收来管理栈内存,垃圾回收只会回收堆内存中的无用对象。

  2. 栈内存分配越大越好吗?

    为栈内存指定大小:-Xss size。例如:-Xss1m、-Xss1024k 栈内存变大了,只会增强方法调用的运行效率,但是线程数量会减少。不建议设置过大的栈内存。

  3. 方法内的局部变量是否线程安全?

  • 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的。
  • 如果局部变量引用了对象,并逃离方法的作用方法,需要考虑线程安全。

栈内存溢出

  • 栈帧过多导致栈内存溢出
  • 栈帧过大导致栈内存溢出
/**
  * 演示栈内存溢出 
  * 结果:抛出异常:java.lang.StackOverflowError
  * -Xss256k
 **/
 public class Demo1_1 {
     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();
     }
 }

线程运行诊断

案例1:cpu占用过多

定位

  • 用top命令定位哪个进程对cpu的占用过高

  • ps -H -eo pid,tid,%cpu | grep 进程id(用ps命令进一步定位是哪个线程引起的cpu占用过高)

  • jstack 进程id

    可以根据进程id找到有问题的线程,进一步定位到问题代码的源码行号