java虚拟机栈的内存结构
[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/JVM/JVM-Memory-Structure-Stack.html
学习JVM的可以去我的GitHub 上查看我的Xmind详细笔记 对整本《深入理解JVM》都有详尽的笔记,帮助理解
一、 前言
Java栈分为两种:
- Java虚拟机栈:
- 描述java【方法】执行的【内存模型】
- 每个线程进入每个方法对应一个栈帧
- 本地方法栈(本文不做描述)
- 同虚拟机栈,区别在于:虚拟机栈服务于Java方法(字节码),本地方法栈服务于Native方法
本文主要讲Java虚拟机栈的内存结构
一图胜千言
二、Java虚拟机栈的组成:
1. 栈帧
每个方法对应一个栈帧,在线程运行到该方法时才创建,随着方法结束而销毁
2. 线程栈
栈帧内存在线程内存上进行分配,每条线程能为栈帧分配的总大小最大值为-Xss
为了方便,我们这里 [把这条线程对应的内存] 称为 [线程栈]
3. Java虚拟机栈
Java虚拟机栈是描述java【方法】执行的【内存模型】–> 实际上它是 当前时刻[
所有的线程栈
]集合的统称
三、 Java虚拟机栈会出现的异常:
经过上面的描述,我们可以清晰地知道:
- 【Java虚拟机栈】由【当前所有的
线程栈
】组成- 【每个线程栈由】由【这条线程所对应的所有
栈帧
】组成
因此,可能会出现2种内存溢出的情况 (也可参考Oracle JavaSE8的JVM规范:The Structure of the Java Virtual Machine-Java Virtual Machine Stacks)
- [x] 线程栈溢出(Stack Overflow):
- 某条线程对应的栈帧内存之和 超过线程栈内存的最大值-Xss
根据栈帧的定义可以理解到:该问题主要是一条线程在某一时间点同时存在于多个方法中(网上称作方法深度过深,最常见的案例就是递归调用)
- 某条线程对应的栈帧内存之和 超过线程栈内存的最大值-Xss
- [x] 从Java虚拟机栈层面溢出(OOM):
当前时刻[
所有的线程栈
]内存之和 超过 Java虚拟机栈所允许的最大值- 导致这个问题的原因是当前新建的线程数太多(当然,换句话也以说是当前计算机可分配给Java虚拟机的空间太少)
每条线程占用的空间都未-Xss,新建多了也就OOM了;这种情况一般较少发生,主要有以下因素:- 系统对线程数上限的限制
- 线程过多,会导致CPU崩溃,也就是说系统早就挂了
- Java虚拟机栈所允许的最大值:JVM 可分配内存-其他JVM内存结构空间最大值(主要是堆)–>剩下的作为栈的总空间最大值(来自《深入理解Java虚拟机》P54)
- 导致这个问题的原因是当前新建的线程数太多(当然,换句话也以说是当前计算机可分配给Java虚拟机的空间太少)
四、验证
4.1. 线程栈溢出(StackOverFlow)
通过-Xss调整线程栈大小测试[线程栈最大占用内存为-Xss]
1 | private static AtomicLong i = new AtomicLong(0); |
运行参数设置-Xss256k -Djava.compiler=NONE
,多次运行输出结果一致:
1 | main 1882 |
运行参数设置-Xss512k -Djava.compiler=NONE
,多次运行输出结果一致:
1 | main 4861 |
2.2.2 从Java虚拟机栈溢出(OOM)
- 注意 Mac有单进程线程数量限制,16G的Mac电脑限制为5000,
修改方式参考(不好意思 不能修改 )- 在一些配置较低的电脑可能会死机,请小心运行
- 建议使用虚拟机运行
影响因素 | 描述 |
---|---|
系统限制 | 系统允许进程的最大线程数 |
-Xss | 每条线程栈占用的内存 |
-Xmx | 堆空间最大值 |
详细验证可以参考
这篇文章
---