《深入理解Java虚拟机》读书笔记1--Java内存区域

《深入理解Java虚拟机》是我个人读过的第一本关于JVM方面的书籍。十分有幸能够读到这本书,在此对作者表示深刻的敬意

不知道有没有人和我一样有类似的情况,就是一本书读完,经过一段时间之后,林林总总最后留在脑子里的并不多,很多东西又还给了作者。有人可能会说,之所以会遗忘,是因为你根本没有理解。我并不否认这点,说实话,很多书读过一遍之后都会存在没有读懂的部分。但是随着我们阅历的丰富以及期间不断的学习,过去不懂的部分终究会慢慢读懂。鉴于这种情况,我觉得读书笔记还是很有必要:读书期间总结归纳,日后温故知新

笔记仅仅是我个人对此书的一份总结,提纲挈领。如需了解细节,请完整阅读原著,这本书我个人也强烈推荐。下面,开始《深入理解Java虚拟机》读书笔记的第一篇--Java内存区域

运行时数据区域

JVM在运行Java程序时将内存区域划分为不同的部分,这些区域有各自的用途以及各自的内存管理策略

在Java虚拟机的概念模型中,这些区域大致可以分为:程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、堆(Heap)、方法区(Method Area)

其中前三者是线程隔离的内存区域,后两者是线程共享的内存区域

1.程序计数器

程序计数器可以简单理解为线程执行字节码的行号指示器。由于在线程切换后需要恢复到程序的执行位置,因此每个线程都有各自的程序计数器

2.虚拟机栈

虚拟机栈描述的是Java方法执行的内存模型,方法在执行的时候会创建栈帧。栈帧用于存储方法执行时所需的局部变量表、操作数栈、动态链接、方法出口等信息。方法的执行伴随着栈帧在虚拟机栈中的入栈及出栈

局部变量表存储了基本数据类型、对象引用、返回地址

Java虚拟机规范对此区域规定了两种异常情况:当线程请求的栈深度大于虚拟机允许的最大深度将触发StackOverflowError;如果虚拟机栈在动态扩展时无法申请到足够的内存将触发OutOfMemoryError

3.本地方法栈

本地方法栈与虚拟机栈作用类似,区别在于虚拟机栈用于Java方法执行,而本地方法栈用于本地方法执行

有些虚拟机甚至不区分本地方法栈和虚拟机栈,而是将它们合二为一

同样本地方法栈也会触发StackOverflowError和OutOfMemoryError

4.堆

堆用于存放对象实例,可以细分为新生代和老年代,进一步可以细分为Eden空间、From Survivor空间、To Survivor空间等。进一步细分区域的目的是根据对象的特征更好的分配以及回收内存空间

堆在物理上可以是不连续的空间,只要在逻辑上是连续的即可。如果当前堆内存已经用完并且无法动态扩展的时候会触发OutOfMemoryError

5.方法区

方法区主要用于存放已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

运行时常量池是方法区的一部分,主要用于存放编译期生成的字面量和符号引用,另外在运行时也可以将新的常量加入池中

这个区域的内存回收通常收益较低,主要是针对常量池的回收以及对类型的卸载(对类型卸载的要求十分严苛)

同样,当方法区无法满足内存分配需求时,将会触发OutOfMemoryError

6.直接内存

直接内存并非Java虚拟机规范中定义的内存区域,但是在大量使用NIO的程序中有可能触发OutOfMemoryError异常

NIO基于Channel和Buffer,可以直接使用本地方法分配堆外内存,然后通过存储在堆中的DirectByteBuffer对象作为这块堆外内存的引用进行操作。虽然堆外内存不会受到Java堆大小的限制,但是仍然会受制于物理内存以及操作系统的限制。当各内存区域总和大于物理内存或者达到操作系统限制,从而导致动态扩展时触发OutOfMemoryError

对象探秘

不同的虚拟机,对于对象的创建、布局和访问会有所差异,下面仅以HotSpot的堆内存为例进行介绍

1.对象的创建

#类检查及类加载

虚拟机在遇到new指令的时候,首先会去常量池检查类的符号引用,如果发现没有对此类进行加载、解析、初始化,那么首先会对该类进行加载

#内存分配

之后虚拟机会为该对象分配内存。由于对象所需内存在类加载后就可以确定,因此分配内存实际上就是从未使用的堆内存中划分出一块确定大小的存储空间。此过程有两种方式:

1)对于规整的堆内存,直接将指针向空闲一侧移动所需的大小,这种方式叫做“指针碰撞”

2)对于不规整对堆内存,虚拟机会维护一个空闲内存列表,当需要分配内存时,划分出一块足够的空间并且更新空闲列表,这种方式叫做“空闲列表”

至于堆内存是否规整连续,取决于具体的垃圾收集器(主要取决于是否带有compact功能)

由于对象的创建是一个十分频繁的过程,在并发情况下会有并发安全的问题。解决的方式有两种:

1)对内存分配进行同步处理,实际上虚拟机采用CAS的方式保证原子性

2)另一种方式是把内存分配的动作按照线程进行隔离,即每个线程会预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。只有在TLAB用完需要新分配的时候在采取同步处理

#初始化零值

内存分配完毕后,虚拟机会对该内存区域初始化零值,如果是TLAB方式,这一步可以提前到TLAB阶段。这一步保证了对象实例属性的初始化。这也就是为什么对象的实例属性可以不赋初值就能够直接访问

#对象头设置

接下来,虚拟机需要将对象进行一些设置,将类的元数据、哈希码、GC分代信息等设置到对象头中

#对象初始化

执行完上述步骤后,对象的实例属性还都是零值,下面会执行<init>方法,按照程序的意图对对象进行初始化(我的理解是执行构造方法)。之后在将对象的引用入栈。至此,对象的创建过程结束

2.对象的内存布局

在HotSpot虚拟机当中,对象的内存布局分为三个区域:对象头、实例数据、对齐填充

#对象头

对象头主要存储两部分信息,一部分是对象的运行时数据(如哈希码、GC分代信息、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等),另一部分是类型指针(即指向类元数据的指针,代表该对象是哪个类的实例。当然类的元数据也并不一定要存储在对象头,这个后续再讨论)

#实例数据

实例数据部分用于存储对象实例的数据,即实例属性的内容,父类的属性也会记录下来。存储顺序会受到虚拟机的分配策略以及字段的定义顺序的影响。默认的分配策略大致有几点规则:

1)会将相同宽度的属性分配在一起

2)满足1的前提下,父类中的属性出现在子类前

3)CompactFields参数为true的时候,会将子类中宽度较窄的属性插入到父类属性的空隙之中

#对齐填充

由于HotSpot虚拟机要求对象的其实地址必须是8字节的整数倍,因此对于对象大小不是8字节整数倍的对象,会被对齐填充

3.对象的访问定位

对象的访问解决的是如何通过栈中对象的引用访问到堆中实际对象的问题,目前主流的方式有两种:

1)句柄访问,栈中对象的引用存储的是对象的句柄地址(句柄在句柄池中维护),句柄存储了堆中对象实例的地址以及方法区中对象的类型数据的地址。

这种方式的优点是引用中存储的是稳定的句柄,当对象地址变化的时候(GC过程中可能会移动对象实例),只需要更新句柄,不需要更新引用;缺点也显而易见,访问对象时多一次指针操作

2)直接指针访问,栈中对象的引用存储的就是对象实例的地址,对象实例(对象头)中又存储了方法区中对象的类型数据的地址

这种方式的优点就是访问迅速(比前者少一次指针操作),在HotSpot虚拟机中采用此种方式

思维导图:

笔记1结束

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

推荐阅读更多精彩内容

  • 就在昨天,老妈和我微信视频,说:听说你买了一辆车。可不是吗?我终于买了一辆自行车。哈哈哈哈,两人不约大笑。 我买了...
    木木木侠阅读 928评论 0 4
  • 金灿灿的玉米囤满农家的庭院 红通通的小枣晾晒在屋前院后 黑黝黝的豆儿装好袋子聚在屋檐下 丰收!今年的秋,农家院落显...
    丰盈仓廪阅读 810评论 0 0
  • 寒风凛冽,寒气袭人,枯草萧疏,绿色尽失,今年的冬天如此苍白凄凉且冷漠. M点燃一支烟,吞云吐雾起来,一圈圈的烟雾,...
    幽谷泉涌阅读 834评论 0 1
  • 01 大熊和小琪是大学同学,也是我认识的人里,唯一一对毕业季在一起,结果谈了三年异地恋的恋人。 上周末,大熊还是失...
    子小洛阅读 3,752评论 47 61