故事:走进JVM的世界(图文并茂)

原文:故事:走进JVM的世界(图文并茂)

走进JVM的世界
  1. 注意!本文较长,建议先收藏再阅读。更多文章可以关注作者公众号:码上实战
  2. 你也可以 star 我的 GitHub上本文所属仓库:https://github.com/flyhero/MarkNote
  3. 说明:本文在 Java 8 Hotspot 64位操作系统下构思

小强是一个工作3年有余的开发工程师,从他的发量你就可以知道,小强资历还尚浅。

程序员惊人发量

最近公司没什么事,他也开始无聊起来了。这天下午,同事们在激烈的讨论这业务,但他没有参与,于是他决定学习些什么知识,无聊的翻着各个网页,发现JVM是各位大神们推荐过的知识,于是决定好好看一看。

5分钟过后……

小强感到这知识有些枯燥乏味,怪不得是大神们能看的!又看了几分钟,小强倦意袭来,揉了揉睡眼惺忪的眼睛。

然而就在这一刻,他突然发现周围同事激烈讨论的声音听不到了,安静到了极致。

1. 入界

小强努力的睁开眼睛,才发现自己竟然身处一个白茫茫的空间中,吓得一跳,心想我这是怎么了,穿越了?但穿越也得穿越到一个人间如画,美女如云的地方啊……,这境地……


JVM幻境

突然前方走来一个白胡子老头,小强正想开口,老头捷足先登:你好,我是这个JVM世界的缔造者,你可以叫我 “HotSpot”,不过这无所谓,因为我所创造的这个世界,是按照 “JVM规范” 来完成的。我正在休息时,发现来了一位客人,原来是你。

小强:我是想问……

老头: 不用问,我知道,你是想了解一下我创造的这个世界吧!跟我来吧。

这老头,我还没说话,这就结束了!好吧,跟你看看且说。

老头边走边道:JVM 的世界 空间是有限的,我们坚持一个原则 : 各司其职,不留无用之人!

小强: 啊!好残酷。

老头: 不,这不是残酷,我们这个世界生来就是为客户提供服务,为客户发光发热的,每个人奉献出了自己的能力就是圆满完成任务,退出舞台是理所应当的,也是他们最好的归宿。

小强:也是,这样这个世界才不会那么拥挤,才能井然有序的工作,我怎么这么不开窍呢……

2. 布局

过来,带你先看看我们世界的整体组成和中心区如何布局。


整体布局

先来看看我们最主要的日常工作区(运行时数据区),为了让我们工作起来更有效率,我们将世界空间划分为这几个板块。

居住区-堆

这里是人们工作外的居住区,居住区我们基于人们的年龄也进一步分出了,伊甸区,幸存者区,老年区。


居住区

工作区-栈

每个任务来临时,都会在工作区单独开辟出一个地方来用于完成这个任务。


栈帧

记录者-程序计数器

由于我们同时能做的任务有限,所以我们需要为不同的任务划分出不同的时间片,我们在切换任务的时候,需要一个记录者,能够记录我们这个任务做到了哪里,下次回来能够继续做。

仓库管理区-方法区

这里存放着工人的模板以及常用的不变的工具等。

3. 生与死

这里工作的人们都会经历生与死,大部分人们活不到老年,但这不重要,重要的是他为我们做出了贡献。

3.1 出生

老头:这里的每个人都有一个模板(类),看到那个正在居住区休息的高个吗?他叫张三,他是根据外部客户给定的模板 “ User Class” 创造的,他可是客户最喜爱的工人了。你知道客户的这些模板(类)是如何进入的到我们的世界中的吗?

小强:这个我知道点,之前看过一点点。这个过程还是有些复杂的,客户的模板(类)是通过一个翻译工厂(编译器) 将它翻译成class 字节码,因为你们这个世界只认识字节码,然后有你们的加载系统将它们加载到这里。

加载过程中有这些阶段:


loading-class.png

其中加载阶段是由加载器来完成的。

老头:是的,我们提供了三种工厂,启动类加载器,扩展类加载器,应用类加载器,当然客户也可以自定义加载器。


parents-delegation.png

小强:他们遵循着双亲委派模型,但是我一直不太理解这个词!

老头: 这是由于你们语言翻译的问题导致,这个模式叫 “parents delegation”,知道了吧!它是指有你的父辈们来帮你完成。

小强:那双亲委派模式 有什么好处呢?

老头:

  1. 具有优先级层次的关系可以避免模板(类)的重复加载
  2. 安全考虑可以防止Java核心api被替换

老头继续道:那连接过程中的三步,你知道是做什么吗?

小强:具体的我就不知道了哎……

老头笑了笑:对于客户定义的模板(类),我们可不是来者不拒的,为了我们这个世界的安全以及能提供更好的服务,我们会对模板做一些验证及后续操作。

验证包括格式验证,元数据验证,字节码验证,符号验证。当验证通过后,我们会为模板所依赖的东西(类变量)分配空间,最后将符号引用替换为直接引用。

老头看了看小强眉头紧皱,于是继续补充:你可能不了解什么是符号引用和直接引用!

符号引用就是在编译时,并不知道模板(类)所依赖的其他东西,会在我们的空间中的哪个位置,只能用符号来表示。

直接引用就是 所有东西被加载到这里后会有自己的真实空间地址,然后去替换符号引用。这样运行时就能找到它们所依赖的东西了。

最后就是初始化了,这个阶段主要是对类变量初始化,是执行类构造器的过程。

小强:我怎么没看到这些模板呢?

老头:这些模板我把他们隐藏在世界的后方,大多数人是见不到的,他们统称为 Klass。

小强:不对啊!你是不是搞错了?不应该叫 Class吗?

老头:哈哈!我刚才说了,大多数人见不到,你就是其中之一啊!你们平时见到的 Class只是对 Klass的一种封装而已,真正记录模板中的具体元信息的就是 Klass。这回要记住了,年轻人。

3.2 工人

小强: 为什么你的工人是等量差的身高呢?


obj-data.png

老头:你的观察还是挺仔细的嘛!是的,他们确实是等量差的,想要知道为什么,要先了解这些工人有哪些部分组成。


obj-length.png

它们头部大小是固定的,身体大小是由自己的属性数据决定的,而最后的脚部却是我来决定的,如果前面两个数据的大小没有达到 8 的倍数,那么我就会来填充,所以就是这里的填充使得他们拥有了等量的身高差(内存对齐)。

我是基于两点原因来这个缔造他们的:

  1. 平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:中央大脑(CPU)访问内存是有内存访问粒度的,就是每次访问内存的长度是固定的,如果不这样做,那么中央大脑起需要访问两次内存,而对齐后只需要一次。

小强:嗯,明白了!那能给我说说这些工人在居住区为什么要不断的搬迁呢?

3.3 成长

老头:经过长时间的观察,我发现每个工人的生命长短是不一样的。所以我把居住区分为新生代,老年代,然后让他们合理的搬迁,这样能有效的利用空间而且让垃圾小分队工作更有效率。


堆区分代

工人诞生后会分配到Eden区,当Eden区人员快满时,垃圾小分队会来清扫,清扫后如果工人还活着,那么他们将搬迁至Survivor区中的其中一个,当这个Survivor快满时,垃圾小分队会将还活着的工人搬迁至另一个Survivor区中,就这样重复着,每经历一次垃圾小分队的清扫,活着的工人就会长大一岁,直到工人的年龄达到15岁,到达后会将他们搬迁至老年代生活的地方。但也有例外,如果某个工人吃的太胖,新生代容不下他,那么他将直接去老年代住下。当老年代快住满时,将会有垃圾大扫除(full gc)。

小强:原来如此啊!从此我再也不是只知道堆区栈区的菜鸟啦!哈哈哈哈……

老头:小伙子,不要高兴太早!你到目前为止所了解的仍是九牛一毛。

3.4 死亡证明

小强:如何确定工人是否到达生命的尽头呢?

第一种:引用计数法

给每个工人添加一个引用计数器,就是只要有人需要这个工人帮忙,那么就给这个工人的计数加1,反之,别人不再需要这个工人的帮忙,那么计数就减1,直到这个计数为0,那么表示这个工人生命到了尽头。

但这种方法有个问题:如果A工人和B工人相互需要帮忙,但没有任何其他工人或任务需要他们两个,那么他们两个会永远活下!所以这种方法我们不会采取的。

第二种:可达性分析法

我们找出被称为 “GC roots”的工人作为起点,依次寻找他们工作中依赖的工人,这就可以知道哪些工人是没有必要在存在下去了。

小强:我怎么知道哪些是 “GC roots”工人呢?

老头:

  1. 工作区(栈)中的需要用到的工人
  2. 仓库(方法区)中模板(类)本身需要的工人(静态,常量)
  3. 世界后方(native方法)需要的工人

小强:Got it!

4. 回收

老头:下面我带你去认识一下垃圾小分队的人物吧!不过在认识他们之前你最好了解一下,垃圾清除的基本方法论。

4.1 基本方法论

收集垃圾遵循的基本方法论有以下几种:

  • 标记-清除

    首先标记出所有需要回收的工人(对象),在标记完成后统一回收所有被标记的工人。

    但这个有两个缺点:1. 效率不高 2. 会产生许多碎片空间

  • 复制

    将可用的空间一分为二,每次只使用其中一块,当快使用完时,小分队回收,然后将活着的工人搬迁至另一块。

    这虽然解决了标记-清除的效率问题,但此种方法却缩小了一半空间。

  • 标记-整理

    首先标记出所有需要回收的工人(对象),然后将存活的工人移动到空间的一端,然后清理掉边界以外的工人。

小强笑了笑:原来是这三种算法啊!我知道!

老头:既然知道,那跟我来认识一下垃圾清扫队的人吧!

4.2 主要成员

垃圾清扫队有好几个小队组成,客户喜欢哪个小队可以指定让谁来工作,他们各个队伍的清扫方式各不相同也各有优劣。

我给你介绍一下两个主要成员吧,CMS,G1两个小队出列。

CMS:到,我们是CMS分队,全称叫 “Concurrent Mark Sweep”,顾名思义,我们是采用标记清除算法的并发小分队,我们以获取最短回收停顿时间为目标。

小强:那你说说你们是如何工作的?

CMS:我们主要分四个步骤工作,1. 初始标记 2.并发标记 3.重新标记 4.并发清除

小强:算啦,这么多步骤太需要时间来了解了,我现在知道你的优点了,那你的缺点有什么呢?

CMS:这怎么还带揭人伤疤的……

老头这时严肃的咳嗽了两声,其意CMS立马捕获到了,委屈的说:

我有三个缺点:

  1. 当资源不是很充足时,占用过多的资源,导致任务变慢
  2. 无法处理浮动垃圾,我们清理的时候,工人同时也在工作,我们标记后,正好有些工人不在需要了
  3. 我们分队遵循的是“标记-清除”算法,所以会产生大量碎片空间,导致世界大扫除(full gc)提前到来

心直口快的小强来了句:原来你的问题这么严重,老头竟然没把你们小分队辞掉……

CMS:你…… 想当年我们分队可是红极一时的……

那么我猜G1是不是可以弥补CMS的不足呢?

G1: 说实话,我们分队的目标就是替换CMS分队…… (JDK14 CMS正式落下帷幕)

小强不怀好意的笑了起来,哈哈……,CMS翻着白眼躲到一旁的角落暗自伤感去了。

角落哭.jpeg

小强:那G1说说你的能耐吧!

G1: 我们队是基于标记整理算法的,因此不会产生大量碎片空间

  • 我们同时引入了分区的思路,弱化了分代的概念

  • 我们的停顿时间是可控的,可避免雪崩现象

  • 我们也能充分利用客户给我们的资源,减少停顿时间

这是我们队的优势,接下来我给你详细介绍下我们队的情况……

小强:好的!你继续……

回归

就在小强听的兴趣浓浓时,天空中突然出现一只巨大无比的手向他袭来,小强躲闪不开,啊……

巴掌.png

小强捂着自己的头,有点恍惚,抬头一看,擦,技术总监……你怎么也在这?

总监:我不在这我在哪?在家睡大觉吗!

这时小强才回过神来,原来自己还在办公室,大事不妙啊!

总监:小强,回家多爽,明天就不用来了吧!

小强一慌,脑袋灵机一动:总监,知道我刚才在做什么吗?那可不是在睡觉,我有一个故事你且听听再做决定。

吧啦吧啦……

最后我将本文知识总结成了思维导图:


思维导图

说明:

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

推荐阅读更多精彩内容

  • Java和C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进来,墙里面的人想出来。 对象...
    胡二囧阅读 1,070评论 0 4
  • 《深入理解Java虚拟机》笔记_第一遍 先取看完这本书(JVM)后必须掌握的部分。 第一部分 走近 Java 从传...
    xiaogmail阅读 5,056评论 1 34
  • JVM有哪些分区?程序计数器,java虚拟机栈,本地方法栈,堆,方法区。 java栈中存放的是一个个栈帧,每一个栈...
    irckwk1阅读 686评论 0 0
  • 介绍JVM中7个区域,然后把每个区域可能造成内存的溢出的情况说明 程序计数器:看做当前线程所执行的字节码行号指示器...
    jemmm阅读 2,222评论 0 9
  • 0. 前言 JVM笔记系列,以JDK1.7为基准,主要以《深入理解Java虚拟机》(第二版)和《Java虚拟机规范...
    郭寻抚阅读 887评论 0 3