JVM内存结构|虚拟机栈

定义

每个线程运行时所需要的内存称为虚拟机栈

  • 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
  • Java 虚拟机栈(Java Virtual Machine Stacks):描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个帧栈(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。它的线程也是私有的,生命周期与线程相同。
  • 局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和 returnAddress 类型(指向了一条字节码指令的地址)。
  • Java 虚拟机栈的局部变量表的空间单位是槽(Slot),其中64位长度的double 和long
    类型会占用两个Slot。局部变量表所需内存空间在编译期完成分配,当进入一个方法时,该方法需要在帧中分配多大的局部变量是完全确定的,在方法运行期间不会改变局部变量表的大小。
  • Java虚拟机栈有两种异常状况:如果线程请求的栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
  • 如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

问题辨析

  • 垃圾回收是否涉及栈内存?
    不涉及。虚拟机栈里的栈帧即对应代码中的一个方法。代码运行的过程,即栈帧入栈出栈的过程。
    一个方法执行完,栈帧出栈后,即被销毁。只有入栈出栈这样简单的操作,不需要设计复杂的垃圾回收算法来回收。随着方法的执行,线程的结束正常回收即可。
  • 栈内存分配越大越好吗?
    不会,栈内存越大线程数目会越少,并不会提高程序的运行效率,但能增加递归的调用次数。
  • 方法内的局部变量是否线程安全?
    如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
    如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

栈内存溢出

java.lang.StackOverFlowError
可能原因:

  • 栈帧过多导致栈内存溢出(方法的递归调用次数过多会导致)

  • 栈帧过大导致栈内存溢出(一个方法的局部变量和方法参数过多,局部变量和方法参数在栈帧中)(不容易出现)

线程运行诊断

案例1:某程序CPU占用过多(Linux下)

定位

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

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

  • jstack 进程id 可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号(查询出的线程id是以十六进制表示的)

案例2:程序运行很长时间没有结果

  • 使用nohup命令运行Java程序获得进程id
  • 使用jstack 进程id,根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号

猜你喜欢

转载自blog.csdn.net/qq_43941925/article/details/114342003