JVM系列-01-JVM内存模型

[TOC]

声明

本篇文章是本人阅读《深入理解JVM》和《java虚拟机规范》时的笔记。
JVM是HotSpot,jdk1.7。
大神绕路,不喜勿喷。

1 JVM内存模型

JVM内存模型

2 程序计数器(PC)

每个线程都会有自己私有的程序计数器(PC)。可以看作是当前线程所执行的字节码的行号指示器。
也可以理解为下一条将要执行的指令的地址或者行号。字节码解释器就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、 循环、 跳转、 异常处理、 线程上下文切换,线程恢复时,都要依赖PC.

  • 如果线程正在执行的是一个Java方法,PC值为正在执行的虚拟机字节码指令的地址
  • 如果线程正在执行的是Native方法,PC值为空(未定义)
JVM内存模型

说白了,PC就是一块内存区域。存放着下一条要执行的指令的地址。

3 虚拟机栈(VM Stack)

3.1 简介

VM Stack也是线程私有的区域。他是java方法执行时的字典:它里面记录了局部变量表、 操作数栈、 动态链接、 方法出口等信息。

在《java虚拟机规范》一书中对这部分的描述如下:

栈帧( Frame)是用来存储数据和部分过程结果的数据结构,同时也被用来处理动态链接 (Dynamic Linking)、 方法返回值和异常分派( Dispatch Exception)。
栈帧随着方法调用而创建,随着方法结束而销毁——无论方法是正常完成还是异常完成(抛出了在方法内未被捕获的异常)都算作方法结束。
栈帧的存储空间分配在 Java 虚拟机栈( §2.5.5)之中,每一个栈帧都有自己的局部变量表( Local Variables, §2.6.1)、操作数栈( OperandStack, §2.6.2)和指向当前方法所属的类的运行时常量池( §2.5.5)的引用。

VM-Stack

说白了,VM Stack是一个,也是一块内存区域
所以,他是有大小的。虽然有大小,但是一般而言,各种虚拟机的实现都支持动态扩展这部分内存。

  • 如果线程请求的栈深度太大,则抛出StackOverflowError
  • 如果动态扩展时没有足够的大小,则抛出OutOfMemoryError

3.2 StackOverflowError

以下代码肯定会导致StackOverflowError:

public static void m1() {
    m1();
}

public static void main(String[] args) {
    m1();
}
Exception in thread "main" java.lang.StackOverflowError
    at xxx.xxx.xxx.m1(JavaVMStackSOF.java:10)

4 本地方法栈(Native Method Stack)

Java 虚拟机实现可能会使用到传统的栈(通常称之为“ C Stacks”)来支持 native 方法( 指使用 Java 以外的其他语言编写的方法)的执行,这个栈就是本地方法栈( Native MethodStack)。

VM Stack是为执行java方法服务的,此处的Native Method Stack是为执行本地方法服务的。
此处的本地方法指定是和具体的底层操作系统层面相关的接口调用了(这部分太高高级了,不想深究……)。

《java虚拟机规范》中没有对这部分做具体的规定。所以就由VM的实现者自由发挥了。
有的虚拟机(比如HotSpot)将VM Stack和Native Method Stack合二为一,所以VM的另一种内存区域图就如下面所示了:

JVM内存模型-虚拟机栈和本地方法栈合二为一

5 Java堆(Heap)

5.1 简介

在 Java 虚拟机中,堆( Heap)是可供各条线程共享的运行时内存区域,也是供所有类实例和数组对象分配内存的区域。

以下是本人对《java虚拟机规范》一书中对Java堆的介绍的总结:

  • 在虚拟机启动的时候就被创建
  • 是所有线程共享的内存区域
  • 存储了被自动内存管理系统所管理的各种对象
    • 这些受管理的对象无需,也无法显式地被销毁
    • 自动内存管理系统:Automatic StorageManagement System,也即是常说的"Garbage Collector(垃圾收集器)"
    • 并未指明用什么具体的技术去实现自动内存管理系统
  • Java 堆的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩
  • Java 堆所使用的内存不需要保证是连续的
  • 如果实际所需的堆超过了自动内存管理系统能提供的最大容量,那 Java 虚拟机将会抛出一个OutOfMemoryError 异常
  • 实现者应当提供给程序员或者最终用户调节 Java 堆初始容量的手段
    • 对于可以动态扩展和收缩 Java 堆来说,则应当提供调节其最大、最小容量的手段
  • 所有的对象实例以及数组都要在堆上分配
JVM-Heap

至于堆内存的详细情况,将在后续的GC相关文章中介绍。

5.2 堆内存中的OutOfMemoryError

以下示例代码肯定导致堆内存溢出:

public static void main(String[] args) {
    ArrayList<Integer> list = Lists.newArrayList();
    while (true) {
        list.add(1);
    }
}

无限制的往list中添加元素,无论你的堆内存分配的多大,都会有溢出的时候。

java.lang.OutOfMemoryError: Java heap space

6 方法区(Method Area)

方法区是由所有线程共享的内存区域。
方法区存储的大致内容如下:

  • 每一个类的结构信息
    • 运行时常量池( Runtime Constant Pool)
    • 字段和方法数据
    • 构造函数和普通方法的字节码内容
  • 类、实例、接口初始化时用到的特殊方法

以下是本人对《java虚拟机规范》一书中对方法区的介绍的总结:

  • 在虚拟机启动的时候被创建
  • 虽然方法区是堆的逻辑组成部分,但是简单的虚拟机实现可以选择在这个区域不实现垃圾收集
  • 不限定实现方法区的内存位置和编译代码的管理策略
  • 容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。
  • 方法区在实际内存空间中可以是不连续的
  • Java 虚拟机实现应当提供给程序员或者最终用户调节方法区初始容量的手段
    • 对于可以动态扩展和收缩方法区来说,则应当提供调节其最大、最小容量的手段
  • 如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个OutOfMemoryError 异常

6.1 运行时常量池(Runtime Constant Pool)

《java虚拟机规范》中对常量池的介绍:

运行时常量池( Runtime Constant Pool)是每一个类或接口的常量池( Constant_Pool,§4.4)的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段引用。
运行时常量池扮演了类似传统语言中符号表( SymbolTable)的角色,不过它存储数据范围比通常意义上的符号表要更为广泛。

运行时常量池

每一个运行时常量池都分配在 Java 虚拟机的方法区之中,在类和接口被加载到虚拟机后,对应的运行时常量池就被创建出来。

  • 当创建类或接口的时候,如果构造运行时常量池所需要的内存空间超过了方法区所能提供的最大值,那 Java 虚拟机将会抛出一个 OutOfMemoryError 异常。

7 直接内存(Direct Memory)

此处的直接内存并不是由JVM管理的内存。他是利用本地方法库直接在java堆之外申请的内存区域。
比如NIO中的DirectByteBuffer就是操作直接内存的。

直接内存的好处就是避免了在java堆和native堆直接同步数据的步骤。但是他并不是由JVM来管理的。

当然,这部分内存区域的操作也可能会抛出OutOfMemoryError

参考文章

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

推荐阅读更多精彩内容

  • JVM内存模型Java虚拟机(Java Virtual Machine=JVM)的内存空间分为五个部分,分别是: ...
    光剑书架上的书阅读 2,477评论 2 26
  • 文章转自 http://blog.csdn.net/u012152619/article/details/4696...
    云狗狗狗狗狗阅读 602评论 1 4
  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,515评论 3 83
  • 四年, 驻足长安, 守望那终南。 今天天气不错, 我们没有课, 以后也不会再有了。
    不争先生阅读 124评论 0 0
  • 这是一个熟悉的城市 我只想守着我的孤单 车水马龙的西安 万国来朝的长安 你只是我旅途的小站 你曾是我梦想的终点 西...
    干国祥备课老干阅读 1,834评论 5 27