简图
线程公有区域:虚拟机栈、本地办法栈和程序计数器
线程共享区域:堆和办法区(元空间区)
线程公有区域
程序计数器
作用:读取程序计数器的值来选取下一条字节码指令,并实现分支、循环、跳转、异样解决、线程回复等
- 程序计数器是一个很小的内容空间,能够看做是以后线程所执行的字节码的行号指示器。在Java虚拟机的概念模型中,字节码解释器工作是通过扭转这个计时器的值来选取下一条须要执行的字节码指令,他是程序控制流的指示器,分支、循环、跳转、异样解决、线程回复等根底性能都须要依赖这个计数器来实现
- 每个线程都有一个独立的线程计数器,各条线程之间计时器互不影响,独立存储。生命周期与线程的生命周期保持一致
- 如果线程正在执行的是一个Java办法,程序计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地办法(调用C类库执行)程序计数器为空(undefined)
- 它是惟一一个在《Java虚拟机标准》中没有规定任何OutOfMemoryError状况的区域
编译如下代码后应用javap
反编译工具查看字节码文件Test.class
public class Test { public static void main(String[] args) { int a = 1; int b = 2; System.out.println(a + b); }}// 指令:javap -v Test.class
在反编译后果中找到main()
办法
途图中红框内的数字为指令地址,执行引擎通过读取指令地址实现办法的运行
虚拟机栈
作用:在Java程序运行期间,它保留办法的局部变量、局部后果,并参加办法的调用和返回
- 每个办法执行的时候,Java虚拟机都会同步创立一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动静链接、办法进口等信息,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
- 属线程公有区域
- 生命周期与线程生命周期雷同
- 此区域规定了两类异样情况:如果线程申请的栈深度大于虚拟机的所容许的深度,将抛出
StackOverFlowError
异样;如果Java虚拟机栈容量能够动静扩大,当栈扩大时无奈申请到足够的内存会抛出OutOfMemoryError
异样 - 应用
-Xss
设置栈的大小;栈的大小间接决定了函数调用的最大可达深度 - 栈的深度通常只有几百K,然而它决定了函数调用深度;如果程序应用了很深的递归函数,而栈空间十分小,此时很有可能产生栈溢出(java.lang.StackOverflowError)
- 对于多线程工作,应放大栈,反之
虚拟机栈的特点:
- 是一种疾速无效的调配存储形式,访问速度仅次于程序计数器
JVM间接对Java栈的操作只有两个:
- 办法的执行对应入栈
- 办法完结执行对应出栈
- 虚拟机栈不存在垃圾回收问题
调整栈的大小
通过在Idea中设置-Xss
参数,察看代码的执行状况
- 设置栈大小为128k,当栈深度为967时抛出栈溢出异样
- 设置栈大小为256k,当栈深度为2250时抛出栈溢出异样
栈帧的内部结构
局部变量表
- 定义为一个数字数组,次要用于存储办法参数和定义在办法体内的局部变量,这些数据类型包含八种根本数据类型、对象援用,以及returnAddress类型
- 局部变量表建设在线程的栈上,是线程公有数据,因而不存在数据安全问题
- 局部变量表所需的容量大小是编译期确定下来的,在运行期间不会扭转局部变量表的大小
- 操作数栈
在办法执行过程中,依据字节码指令,往栈中写入数据或提取数据,即入栈和出栈。应用javap指令可查看操作数栈的深度
- 动静链接
每一个栈帧外部都蕴含一个指向运行时常量池中该帧所属办法的援用。蕴含这个援用的目标就是为了以后办法的代码可能实现动静链接。动静链接的作用是将符号援用转换为调用办法的间接援用。
办法返回地址
寄存调用该办法的的PC寄存器的值 ;程序失常退出时返回该值,异样退出时不返回该值
- 一些附加信息
本地办法栈
本地办法栈用于治理本地办法的调用(c或c++),会抛出StackOverFlowError
和OutOfMemoryError
线程共享区域
堆
- 一个Java过程对应一个JVM实例,一个JVM实例存在一个运行时数据区,多个线程共享堆和办法区
JVM启动时堆被创立且空间大小以确定,是JVM 治理的最大的一个内存区域
- 堆的大小是可调节的
- 堆能够处于物理不间断,但在逻辑上应该是视为间断的
- 所有的线程共享堆,还能够划分出线程公有缓冲区(TLAB)
- 大多数对象实例和数组都调配在堆上
- 数组和对象可能永远不会存储在栈上,栈帧中保留援用,援用指向堆中的地位
- 办法执行完结后,堆中的对象不会立刻移除,在垃圾收集的时候才会被移除
- 此区域是GC的次要工作区域
细分堆内存
Java7及之前
- 年老代
- 老年代
- 永恒代
Java8及之后
年老代
- Eden Space、Survivor0、Survivor1
- 老年代 :Old Gen
- 元空间:Metaspace
设置堆空间的的大小
-Xms
:memory start; 用来设置堆(年老代+老年代)的初始内存大小
-Xmx
:memory max;用来设置堆(年老代+老年代)的最大内存大小
-XX:+PrintGCDetails 输入GC信息
年老代和老年代
- 应用
-XX:NewRatio
调整年老代和老年代的比例,例如:-XX:NewRatio=3,示意年老代占1份,老年代占3份;对应四分之一和四分之三 - 默认状况下
-XX:NewRatio=2
- 年老代中的分配比例为8:1:1,应用
-XX:-UseAdaptiveSizePolicy
敞开自适应内存调配策略 - 应用
-Xn
设置年老代的空间
办法区
参考资料
- 【Java虚拟机探索】5.罕用JVM配置参数-栈的调配参数
- 深刻了解Java虚拟机-周志明(第二版)