JVM内存结构:虚拟机栈 栈内存溢出 线程诊断

JVM内存结构:虚拟机栈

在这里插入图片描述

虚拟机栈是什么

Java Virtual Machine Stacks,Java虚拟机栈

  • 每个线程运行所需要的内存,就是虚拟机栈
  • 每个栈内部有多个栈帧(Frame),对应线程中正在运行的方法执行时需要的内存
  • 每个线程只能有一个活动栈帧,对应该线程正在执行的方法

虚拟机栈结构

在idea中如何看到虚拟机栈情况

调试模式下,查看debuger的frame即可。
如下图,可以看到虚拟机栈中存在 main,method1,method2三个方法的栈帧信息。
此时正运行method2,则method2处于虚拟机栈的顶部,也就是活动栈帧。
右侧 Variable 显示当前方法运行的局部变量。
当方法调用结束,method2弹出栈,局部变量内存被释放。
再执行时,会执行在method1栈帧中记录的地址,也就是之前调用方的位置。
虚拟机栈的演示

面试问题:垃圾回收是否涉及栈内存?

不需要。栈内存中保存调用方法的局部变量,方法返回后,栈帧直接回收,不需要等到垃圾回收。

栈内存默认大小?

从文档上可以看到,
linux,macOS,Oracle Solar,Windows等操作系统中,栈内存大小一般为1M。(这里的栈指的是一个线程对应的栈内存)
虚拟机栈文档

如何指定栈内存大小?

使用 -Xss Size 参数可以设置虚拟机栈的大小。
例如:
-Xss1m
-Xss1024kb
指定栈内存大小1
指定栈内存大小2

面试问题:栈内存越大越好吗?

不是。物理内存有限,当设置栈内存越大,线程数量就越少。反而容易影响性能。一般使用系统默认的栈大小就可以了。

面试问题:方法内部的局部变量是否线程安全

是的。
线程安全是指,某个资源,多个线程可以操作,并且有机会同时访问,就可能会有线程安全问题。
方法内部的局部变量,只在一个线程内,不会有多个线程访问。
但是如果是线程以外的变量,如 静态变量,就可能会出现线程安全问题。

  1. 如果方法内部的局部变量,没有逃离方法的作用访问(既不是参数,也不是返回值),那么就是线程安全的
  2. 如果局部变量引用了对象,并且逃离了方法的作用访问(是方法的参数,或者是返回值),那么需要考虑线程安全问题

栈内存溢出是什么错误信息

java.lang.StackOverflowError

什么情况会导致栈内存溢出

  • 栈帧过多会导致栈内存溢出(要注意递归中终结条件,对象循环引用问题)
  • 栈帧过大会导致栈内存溢出(一般不会出现这种情况)
    栈帧过多
    栈帧过大

对象循环引用问题是什么,为什么会导致栈溢出

对象循环引用,如下图,Emp 和 Dept相互引用对方作为成员变量,并且在转换 json的时候,导致一直循环,最后栈溢出。
对象循环引用
json转换

线程运行诊断

案例1:cpu占用过多

问题:程序运行过程中,cpu占用超过90%
思路:查看占用 cpu 最高的进程、线程,再使用 jstack 查看该线程的虚拟机栈,在栈中找到正在运行的代码的行
定位:

  1. 准备一个linux环境:Xshell登录虚拟机
  2. 使用 nohup 命令运行程序,nohup java程序
  3. 使用 top 命令,查看linux的cpu占用情况,top
    在这里插入图片描述
  4. 查看cpu占用情况,发现最高占用的进程的PID为32655,cpu占用达到99%
    cpu占用情况
  5. 使用 ps命令,查看进程内部的线程对CPU 的占用情况
    ps H -eo pid,tid,%cpu
    H 打印进程中所有线程
    -eo 后面增加需要打印的内容
    pid 进程id
    tid 线程id
    %cpu cpu占用百分比
    ps命令
    可以看到进程 32655 线程 32665 的cpu占用最高

ps H -eo pid,tid,%cpu | grep 32655
仅查看进程为 32655的所有线程

  1. jstack命令查看进程下的所有线程的虚拟机栈情况
    jstack 进程id
    如案例中, 输入 jstack 32655,可以看到这个进程下所有的线程。查找线程id为32665的线程,是看 nid,这个nid使用了十六进制表示,那么将32665转换成十六进制,就是 0x7f99,找到对应的线程thread1。看栈中信息,发现顶端栈帧中,运行到Demo1_16.java文件的第8行,定位成功。
    jstack命令

案例2:程序运行很久没有结果

问题:程序运行很久都没有结果
思路:可能是线程出现了死锁
定位:

  1. 准备一个linux环境:Xshell登录虚拟机
  2. 使用 nohup 命令运行程序,nohup java程序
  3. 使用 jstack 命令查看正在运行程序的进程 id对应的虚拟机栈信息

jstack 进程id
在这里插入图片描述

  1. 查看后发现,此进程中,输出了线程死锁错误,分别卡在Demo1_3.java的29行和 21行。thread0锁住了对象A,想要去所住对象B。thread1锁住了对象B,想要去锁对象A,于是相互等待,形成死锁。
    ``
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值