从HelloWo从HelloWorld.class讲内存到底是如何进行分配的?

很多人问,作为一个Android开发有必要了解Java内存分配机制吗?答案是肯定的。

java的内存区域划分实际上远比这复杂:java虚拟机在执行Java
程序的过程中会把所有的内存划分为不同的数据区域,下面这张图
描述了一个HelloWorld.java文件被JVM加载到内存中的过程:


1.HelloWorld.java 文件首先需要经过编译器编译,生成HelloWorld.class 字节码文件。

2.Java程序中访问HelloWorld这个类时,需要通过ClassLoader将HelloWorld.class加载到JVM内存中。

3.JVM中的内存可以划分为若干个不同的数据区域,包括:
程序计数器,虚拟机栈,本地方法栈,堆,方法区

1.1 程序计数器

Java是多线程的,CPU可以在多个线程中分配执行时间片段。当一个线程被CPU挂起时,需要记录代码已经执行到的位置,方便CPU重新执行此线程时,知道从那行执行开始执行,这就是程序计数器的组作用。

程序计数器是虚拟机中一块较小的内存空间,主要用于记录当前线程
执行的位置。


如上图所示:每个线程都会记录当前方法执行到的一个位置,当CPU切换到某一个线程上时,根据程序计数器记录的数字,继续向下执行指令。

关于程序计数器还有几个需要格外注意:

1.在Java虚拟机规范中,对程序计数器这一区域规定没有任何OutOfMemoryError情况。

2.线程私有,每个线程内部都有一个私有的程序计数器,他的生命周期随着线程创建而创建,结束而死亡。

3.当一个线程正在执行一个Java方法时,这个程序计数器记录正在执行虚拟机字节指令的地址,如果正在执行的是Native方法,这个程序计数器的数值为空

1.2本地方法栈

本地方法栈和下面即将要讲的虚拟机栈基本相同,只不过是针对本地方法,在Android开发涉及JNI可能接触本地方法多一些,有一些虚拟机的实现已经将本地方法栈和虚拟机栈合二为一了(HotSpot)。

1.3虚拟机栈

虚拟机栈也是线程私有的,与线程的生命周期同步,在Java虚拟机中,规定了两种异常:

1.StackOverflowError :当前线程请求栈深度超出虚拟机栈所允许的深度时抛出。

2.OutOfMemoryError:当JVM动态扩展到无法申请足够内存时抛出。

在我们看一些博客和书的时候,经常看到一句话:JVM是基于栈解释器执行的,DVM是基于寄存器解释器执行的。

上面那句话基于栈值得就是虚拟机栈,虚拟机栈的初衷是用来描述Java方法执行的内存模型,每个方法执行的时候,JVM都会在虚拟机栈中创建一个栈帧,让我们看一下栈帧是什么?

1.3.1栈帧

每一个线程在执行某一个方法时,都会为这个方法创建一个栈帧,
我们可以这样理解:一个线程包含多个栈帧,每个栈帧内部包含:局部变量表,操作数栈,动态链接,返回地址等。


1.3.1.1 局部变量表

局部变量表是变量值的存储空间,我们调用方法传递的参数,以及在方法内部创建的变量都会保存在局部变量表中。

1.3.1.2 操作数栈

操作数栈也常称为操作栈,他是一个后入先出栈。
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法执行的过程中,会把各种指令压入和弹出操作数栈。

1.3.1.3 动态链接

动态链接的主要目的是为了支持方法在调用过程中的动态链接。

在一个class文件中,一个方法要调用其他方法,需要将这些方法的符号引用转化为其所在内存地址中的直接引用,而符号引用存在于方法区中。

1.3.1.4 返回地址

当一个方法开始执行后,只有两种方式可以退出这个方法:

1.正常退出:方法中的代码正常完成,或者遇到任意一个返回的指令。
2.异常退出:方法执行过程中遇到异常,并且内部没有处理。

正常退出时,栈帧中可能保存此数值作为返回地址。方法异常退出时,栈帧中一般不会保存部分信息。

1.4 堆

Java堆是JVM所管理的内存中最大的一块,该区的唯一目的就是存放对象实例,几乎所有的对象的实例都在堆里分配,因此他是GC管理的主要区域,有时候也叫GC堆同时他是所有线程的内存区域,因此被分配在此区域的对象如果被多个线程访问的话,需要考虑线程安全。

按照对象存储时间的不同,可以分为新生代,老年代,其中新生代又被分为Eden和Survivor区。

图中不同的区域具有不同的生命周期,可以根据不同区域使用不同的垃圾回收算法,进而提高垃圾回收率。

1.5 方法区

方法区也是JVM规范里规定的一块运行时数据区。主要存储已经被JVM加载的类信息(版本,字段,方法,接口),常量,静态变量,即时编译器后的代码和数据,该区域也是被各个线程共享。

1.6 异常再现

StackOverflowError 栈溢出:

在method方法中,递归调用了自身,并且没有设置递归结束条件,所以出现了StackOverflowError异常。

OutOfMemoryError 内存溢出:
理论上,虚拟机栈,方法去,堆都有可能发生OutOfMemoryError,但在实际过程中,大多数发生于堆中。

在一个无线循环中,动态向List添加HeapError对象,这会不断的占用堆中的内存,当堆内存不够时,必然会产生OutOfMemoryError,也就是内存溢出异常。

1.7 总结

对于 JVM 运行时内存布局,我们需要始终记住一点:上面介绍的这 5 块内容都是在 Java 虚拟机规范中定义的规则,这些规则只是描述了各个区域是负责做什么事情、存储什么样的数据、如何处理异常、是否允许线程间共享等。千万不要将它们理解为虚拟机的“具体实现”,虚拟机的具体实现有很多,比如 Sun 公司的 HotSpot、JRocket、IBM J9、以及我们非常熟悉的 Android Dalvik 和 ART 等。这些具体实现在符合上面 5 种运行时数据区的前提下,又各自有不同的实现方式。

最后我们借助一张图来概括一下本课时所介绍的内容:


总结来说,JVM 的运行时内存结构中一共有两个“栈”和一个“堆”,分别是:Java 虚拟机栈和本地方法栈,以及“GC堆”和方法区。除此之外还有一个程序计数器,但是我们开发者几乎不会用到这一部分,所以并不是重点学习内容。 JVM 内存中只有堆和方法区是线程共享的数据区域,其它区域都是线程私有的。并且程序计数器是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域。

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

推荐阅读更多精彩内容

  • 如果有需要,书籍地址 JVM 中的内存可以划分为若干个不同的数据区域,主要分为:程序计数器、虚拟机栈、本地方法栈、...
    XII01阅读 425评论 0 0
  • Java内存区域直接划分为堆内存和栈内存并不完全准确 JVM 中的内存可以划分为若干个不同的数据区域,主要分为:程...
    NC丶脑补东阅读 565评论 0 4
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,528评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,572评论 0 11
  • 可爱进取,孤独成精。努力飞翔,天堂翱翔。战争美好,孤独进取。胆大飞翔,成就辉煌。努力进取,遥望,和谐家园。可爱游走...
    赵原野阅读 2,738评论 1 1