Java代码是要运行在虚拟机上的,而虚拟机在执行Java程序的过程中会把所管理的内存划分为若干个不同的数据区域,这些区域都有各自的用途。其中有些区域随着虚拟机进程的启动而存在;而有些区域则依赖用户线程的启动和结束而建立和销毁,其生命周期与线程保持一致。
在《Java虚拟机规范(Java SE 8)》中描述了JVM运行时内存区域,划分为五个区域,结构如下: 三种JVM:
Sun公司的HotSpotBEA公司的JRockitIBM公司的J9 JVM在JDK1.7及其以前我们所使用的都是Sun公司的HotSpot,但由于Sun公司和BEA公司都被Oracle收购,JDK1.8采用Sun公司的HotSpot和BEA公司的JRockit两个JVM中精华形成JDK1.8的JVM。
属于线程私有的数据区域,是一个非常小的内存空间,几乎可以忽略不计。主要代表当前线程所执行的字节码行号指示器。字节码解释器工作时,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
方法区属于线程共享的内存区域,又称Non-Heap(非堆),主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,根据Java虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。值得注意的是在方法区中存在一个叫运行时常量池(Runtime Constant Pool)的区域,它主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用。
属于线程私有的数据区域,与线程同时创建,总数与线程关联,代表Java方法执行的内存模型。每个方法执行时都会创建一个栈桢来存储方法的的变量表、操作数栈、动态链接方法、返回值、返回地址等信息。每个方法从调用直结束就对于一个栈桢在虚拟机栈中的入栈和出栈过程,如下(图有误,应该为栈桢):
Java堆也是属于线程共享的内存区域,它在虚拟机启动时创建,是Java虚拟机所管理的内存中最大的一块,主要用于存放对象实例,几乎所有的对象实例都在这里分配内存,注意Java堆是垃圾收集器管理的主要区域,因此很多时候也被称做GC堆,如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
本地方法栈属于线程私有的数据区域,这部分主要与虚拟机用到的Native方法相关,一般情况下,我们无需关心此区域。 本地方法栈十分类似Java虚拟机栈,与Java虚拟机区别在于服务对象: 即Java虚拟机栈为执行 Java 方法服务;本地方法栈为执行 Native方法服务
默认最小值为16MB,最大值为64MB,可以通过-XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小
JVM内存结构,由Java虚拟机规范定义,描述的是Java程序执行过程中。由JVM管理的不同数据区域,各个区域有其特定的功能。
JVM内存结构 与 Java内存模型(Java Memory Model 简称JMM),这两种划分是属于两种不同层次的概念,可以说是毫无关联,千万不要搞混淆了。
JVM内存结构,和Java虚拟机的运行时区域有关。 Java内存模型,和Java的并发编程有关。