JVM 执行 Java 程序时的内存区域划分

JVM Memory Layout

在学习 Java 虚拟机(后面简称:JVM)中的垃圾回收机制(GC)之前,先需要了解 在 JVM 中的 Java 程序(class 文件)加载到内存之后到底是怎么存的。在阅读了JVM规范和周志明的《深入理解Java虚拟机(第2版)》之后,总结一下JVM中的内存划分以及各个区域的作用。

在JVM规范中定义了5种运行时的数据区域:程序计数器(Program Counter Register)、Java虚拟机栈(JVM Stacks)、堆(Heap)、方法区(Method Area)、运行时常量池(Runtime Constant Pool)、本地方法栈(Native Method Stack)。在周志明的书中还提到了直接内存(Direct Memory),它并不是JVM运行时数据区域的一部分,在JVM的规范中也没有相关的定义。下面分别来说明各自的用途。

程序计数器

程序计数器,也叫PC Register。它的用途很单一,但是却是很多功能的基础。如果线程当前执行的是Native方法,那么寄存器里的值就是Undefined;如果线程当前执行的是非Native方法,那么寄存器里的值就是当前执行的JVM字节码指令的地址。像我们常用的分支、循环、跳转、异常处理、线程恢复等都依赖于它。

由于JVM支持多个线程同时执行,所以每个线程都有一个独立的程序计数器,各个线程互不影响,这类内存区域也称之为线程私有的。

Java虚拟机栈

虚拟机栈也是线程私有的,随着一个线程的创建而创建,主要用来存储栈帧(Stack Frame)。什么是栈帧呢?在Java中,每个方法在执行时就会先创建一个栈帧并放入虚拟机栈中,在方法执行完毕时再从虚拟机栈中移除该栈帧。它主要用来存储局部变量表、操作数栈、动态链接、方法出口等信息。我们常说的堆(Heap)和栈(Stack)中的栈,指的就是虚拟机栈。

在JVM规范中并没有对虚拟机栈空间的大小做限制,可以设置为固定大小的,也可以设置为可扩展的。但是在规范中定义了两种异常情况:

  • 如果计算时请求的栈空间大于虚拟机栈的最大值,则会抛出StackOverflowError异常;
  • 如果虚拟机栈设置为可扩展的并且无法再获取更多内存时,则会抛出OutOfMemoryError异常。

相比而言,堆在JVM管理的内存区域中属于最大的一块,随着虚拟机的启动而创建,用来存储所有的class实例和数组,所有线程共享这一区域,该区域也是垃圾回收的主要区域。虽然JVM规范中说所有的对象实例都在该区域分配空间,但是随着JIT技术的逐步发展,这一说法也不严谨了。

堆空间的大小也可以设置为固定大小,或者可扩展的。但不管是何种方式,规范中还是定义了一种异常场景:

  • 如果计算需要更多的堆空间而无法满足时,则会抛出OutOfMemoryError异常。

方法区

方法区和堆一样,也是随着虚拟机启动而创建,所有线程共享,主要用来存储被JVM加载的类信息、常量、静态变量等信息。

JVM规范中并未严格要求要对该区域进行垃圾回收,但是HotSpot虚拟机在垃圾回收的时候还是会考虑该区域,在分代垃圾回收中所说的“永久代”指的就是方法区。方法区的大小也可以设置为固定大小,或者可扩展的。但不管是何种方式,规范中还是定义了一种异常场景:

  • 如果计算需要更多的方法区空间而无法满足时,则会抛出OutOfMemoryError异常。

运行时常量池

运行时常量池是方法区的一部分,用于存储编译期生成的各种字面量和符号引用。在Java中并不要求常量一定只有编译期才能产生,运行期间也可能将新的常量放入池中,例如String类的intern()方法。

每个运行时常量池都是随着一个类或者接口的创建而创建的。在规范中定义了一种异常场景:

  • 在创建一个类或者接口时,如果运行时的常量池无法分配到足够的空间时,则会抛出OutOfMemoryError异常。

本地方法栈

本地方法栈和虚拟机栈类似,也是线程私有的,随着一个线程的创建而创建,只不过虚拟机栈是用来服务Java方法调用,而本地方法栈是用来服务本地方法调用的。

在JVM规范中并没有对本地方法栈空间的大小做限制,可以设置为固定大小的,也可以设置为可扩展的。在规范中也定义了两种异常情况:

  • 如果计算时请求的栈空间大于本地方法栈的最大值,则会抛出StackOverflowError异常;
  • 如果本地方法栈设置为可扩展的并且无法再获取更多内存时,则会抛出OutOfMemoryError异常。

直接内存*

直接内存不受虚拟机参数的控制,在NIO中有一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以通过Native方法在堆外分配内存,然后通过DirectByteBuffer对象来引用这块内存。因为避免了在Java堆和Native堆之间来回复制数据,从而在某些场景中能够得到性能的提升。一旦使用的直接内存超过了物理内存的总和,则会抛出OutOfMemoryError异常。

参考链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容