运行时内存区域
java虚拟机在执行Java程序的过程中,会将它管理的内存划分成若干不同的数据区域。jdk1.8之前和之后的版本有些不同
jdk1.8之前
jdk1.8之后
线程私有内存区域
线程共享的内存区域的生命周期随着线程的创建而建立,随着线程的结束而销毁
- 程序计数器
程序计数器是一块很小的内存空间,可以看作虚拟机运行二进制字节码的行号指示器。字节码解释器就是通过改变程序计数器的取值来获取下一条需要执行的字节码指令。
如果线程正在执行的是Java代码,那么程序计数器记录的是正在执行的字节码指令的地址,如果是native本地方法,程序计数器记录的则是空(Undefined)
程序计数器是唯一一个不会出现OutOfMemoryError的内存区域
- Java虚拟机栈
虚拟机栈描述的是Java方法运行的内存模型,每个方法在执行的同时会创建一个栈帧,用于存放局部变量表,操作数栈,动态连接,方法出口等信息。每一个方法的调用到执行完成对应一个栈帧的入栈和出栈的过程。
局部变量表 :是一组变量值存储空间,用来存放方法参数和方法内部定义的变量
操作数栈 :也被称为操作栈,它是一个后入先出栈,当一个方法刚刚开始执行的时候,操作数栈中还是空的,在方法的执行过程中,会有各种的字节码指令往操作数栈中写入或提取内容,对应入栈和出栈。操作数栈相当于操作系统中用来存储接下来要被处理数据的寄存器。虚拟机将虚拟机栈作为他的工作区-大多数指令都要在这里弹出数据,执行计算,然后将结果压回虚拟机栈,然后将将结果存到局部变量表。
在概念模型中,两个栈帧是完全独立的,但是在实际使用中,会做一些优化,令两个栈桢出现一部分重叠,这样在进行方法调用的时候可以共用一部分数据,无需进行额外的参数复制传递。
动态连接 :每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有该引用是为了支持方法调用过程中的动态连接。
在这个区域中,java虚拟机规定了两种异常状况:如果线程请求的栈深度大于虚拟机允许的栈深度,将会抛出StackOverflowError异常,如果虚拟机可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryErrory异常。
栈帧是方法运行时的基础数据结构。
- 本地方法栈
本地方法栈与虚拟机栈发挥的作用很相似,区别在于,虚拟机栈是为虚拟机执行java方法服务,本地方法栈是为native方法服务,有的虚拟机甚至将本地方法栈与虚拟机栈合二为一。
线程共享的内存区域
- Java堆
对于大多数应用来说,堆(Java Heap)是Java虚拟机管理的最大的内存,在Java虚拟机启动的时候创建,此内存区域唯一目的是存放对象实例,几乎所有的对象实例都在这里分配内存。包括数组都要在这里分配内存
Java堆是垃圾收集器管理的主要区域,所以也叫做GC堆。
根据Java虚拟机的规定,Java堆可以是物理上不连续的内存空间,在实现上可以设置成可扩展的(通过参数-Xmx和-Xms来控制),如果堆中没有内存进行实例分配并且堆无法扩展,则会抛出OutOfMemoryError异常。
-
Java方法区
方法区和堆一样,是各个线程共享的内存区域,它用来存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码数据,虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与 Java 堆区分开来。
java方法区也被称为永久代(HotSpot)
JDK1.8之前永久代还没有被移除的时候通过下面的参数设置大小
-XX:PermSize=N //方法区 (永久代) 初始大小
-XX:MaxPermSize=N //方法区 (永久代) 最大大小,超过这个值将会抛出 OutOfMemoryError 异常:java.lang.OutOfMemoryError: PermGen
jdk1.8之后,方法区被彻底移除了,取而代之的是元空间,元空间使用的是直接内存。
-XX:MetaspaceSize=N //设置 Metaspace 的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置 Metaspace 的最大大小
与永久代很大的不同就是,如果不指定大小的话,随着更多类的创建,虚拟机会耗尽所有可用的系统内存。
为什么使用元空间取代方法区 ?
- 永久代有一个 JVM 本身设置固定大小上限,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。
- 运行时常量池
运行时常量池是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用)
JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。
原文
https://segmentfault.com/a/1190000022315329