JAVA运行时数据区

Java与C++之间有一堵由内存动态分配和自动垃圾回收技术围城的墙,墙里面的人想出来,墙外面的人想出去。
关于虚拟机的内存区域和内存异常,分两个部分,第一个部分是运行时数据区及其对应的异常类型,第二个部分是在内存区域中创建对象的原理。本篇主要涉及第一个部分,第二个部分参考JAVA运行时数据区对象创建原理

运行时数据区

java虚拟机运行时数据区包括五部分,平常大家最关心的也是最常说的就是堆和栈,严格意义上来讲并不是十分准确。java虚拟机运行时数据区包括如下五部分:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈
  • 方法区
    如下图:


    image.png

下面就分别说一下这几个区域的相关信息。
按照声明周期或者与线程的关系,可以分为两类。线程私有和线程共享:线程私有的为程序计数器、虚拟机栈、本地方法栈;线程共享的为堆和方法区。

程序计数器

程序计数器是很小的一块内存空间,记录的是当前程序执行的字节码的行号显示器。虚拟机需要执行哪条字节码就是由程序计数器的内容确定的。不管是分支、循环、跳转、异常处理等等,都是通过修改程序计数器的值来达到控制虚拟机执行哪条字节码指令。当然,如果当前程序调用了本地方法,那么程序计数器的值有可能是空的。
该区域在java虚拟机规范中唯一一块没有规定任何内存异常信息的区域。
总结来讲,程序计数器可以概括为:

  • 内存空间小
  • 声明周期跟所属线程相同
  • 内容是程序执行的字节码行号
  • 内容可以为null
  • 没有任何内存异常

虚拟机栈

虚拟机栈跟程序计数器一样,也是线程私有的,其生命周期跟所属线程相同。
虚拟机栈的内容描述的是java方法执行时的内存模型。java方法的每次调用和执行完成返回都会对应一个叫做栈帧的数据结构在虚拟机栈中的入栈和出站操作。栈帧存储的是java方法执行时的局部变量表,操作数、动态链接和方法出口灯信息。栈帧的具体接口这里不做展开,后边会专门讲。
局部变量表中存储的是编译期可知的基本数据类型,对象引用和returnAddress类型。基本数据类型就是java中大家所熟知的八种基本数据类型(boolean、byte、char、short、int、float、double、long),对象引用可能是一个对象实例起始地址的指针,可能是指向对象地址的一个句柄,也可能是代表该对象位置相关的地址(关于是指针还是句柄,参看JAVA运行时数据区对象创建原理 中的 对象定位 小节 )。基本数据类型中,long和double占用了两个局部变量空间,由于long和double都是占用了8个字节,所以可知一个局部变量空间是4个字节。
在java虚拟机规范中对该区域规定了两种异常:如果线程请求的栈深度超过虚拟机允许的深度,将抛出StackOverflowError异常,典型的场景就是递归调用。虚拟机栈动态扩展申请内存时,如果申请不到足够的内存,则会抛出OutOfMemoryError。
总结来讲,虚拟机栈可以概括为:

  • 声明周期跟所属线程相同
  • 内容描述的是java方法执行时的内存模型,包括局部变量表、操作数、动态链接、方法出口灯信息
  • 局部变量表中存储的是编译器就确定的基本数据类型,大小在编译器就确定,运行过程中大小不会改变
  • 会抛出两种运行时区域的异常:StackOverflowError和OutOfMemoryError

本地方法栈

本地方法栈和虚拟机栈类似,只不过是虚拟机栈是虚拟机执行java方法时所需要的,而本地方法栈是虚拟机使用到Native方法是所需要的。

堆是java虚拟机管理的内存中空间最大的一块。该区域是被所有线程共享的一块内存区域。在虚拟机启动的时候创建,其大小可以通过-Xmx和-Xms来设置最大值和最小值。此区域的内容是存放对象实例,也包括数组。不过随着JIT编译器的发展和逃逸分析技术的不断成熟,栈上分配和标量替换也会导致所有对象实例都在堆上分配不是那么绝对了。
从内存垃圾回收的角度来看,堆也是垃圾回收器管理的主要区域。可以分为年轻代和年老代,更详细一些可分为Eden空间,From Survivor空间和To Survivor空间。从内存分配角度来看的话,虽然该区域是线程共享的,但是可能会划分出多个线程私有的分配缓冲区(TLAB)。但是不管从哪个角度,如何划分,都与存放的内容无关,无论哪个区域,存放的都是对象实例。
当申请新的内存是,如果没有足够的内存空间来申请,则会抛出OutOfMemoryError异常。
总结来讲,堆可以概括为:

  • 堆是虚拟机管理的空间中最大的一块内存空间
  • 堆的声明周期是不随线程变化的,跟虚拟机相同
  • 存放的内容是java对象实例,但是随着JIT编译技术的发展和逃逸分析技术的成熟,所有的对象都在堆中分配不是特别绝对了,也有可能在栈上分配或者标量替换
  • 这是垃圾回收的主要区域,线程共享的该区域可能会划分出多个线程私有的分配缓冲区(TLAB:Thread Local Allocation Buffer,这个区域的左右是为了在共享内存中多个线程都并发申请分配内存时解决内存冲突的一种手段)
  • 会抛出OutOfMemoryError异常

方法区

方法区是线程共享的一块内存区域,虽然叫方法区,但是却与方法没有任何关系。方法区存储的内容是虚拟机加载的类信息、静态变量、常量以及及时编译器编译后的代码数据。
也有人称方法区为“永久代”,但是使用“永久代”代替方法区并不是很好的选择,容易遇到内存溢出的问题。从1.7开始,原本放在该区域的字符串常量池已经被移除,该有Native Memory来实现了。跟区域和java堆一样,可以不需要连续的内存(物理上不一定是连续的,逻辑上是连续的即可),可以选择固定大小和扩展。不同的是可以选择不进行垃圾回收,该区域垃圾回收主要操作是对常量池的回收和类型的卸载。
当方法区无法满足申请内存需求时,也会抛出OutOfMemoryError。
总结来说,方法区可以概括为:

  • 线程共享的内存区域
  • 生命周期跟虚拟机一样,与线程无关
  • 可以不实现垃圾收集,如果收集,主要是针对常量池的回收和类型的卸载
  • 方法区大小可以固定,也可以扩大或缩小,方法区内存不需要是连续物理空间
  • 会抛出OutOfMemoryError异常

运行时常量池

运行时常量池是方法区的一部分。Class类文件中除了有类的版本、字段、方法、接口等元数据外;还有一项信息是常量池,存放的编译器生成的各种字面量和符合引用,也就是静态变量和常量。这些内容将在类加载后进入方法区的运行时常量池。
类的常量池和运行时常量池有两个不同:
一、类的常量池是被java虚拟机规范严格规定的,每个字节用于存储那种数据必须符合规范上的要求,虚拟机才可以正确的解析。但对于运行时常量池而言,虚拟机规范没有任何细节上的要求。
二、类的常量池是静态的,一旦编译后就确定了,而运行时常量池是动态的,典型的就是String的intern()方法会在运行期间产生新的字符串常量存入运行时常量池中。

直接内存

直接内存不是java虚拟机规范中定义的内存区域,也不是java虚拟机运行时的数据区域,而是机器的内存。这部分区域也会被频繁的使用,如果-Xmx等参数设置不合理,也可能造成OutOfMomeryError异常。
自从jdk1.4加入了NOI后,引入了通道(Channel)和缓冲去(Buffer)的方式,可以使用Natvie函数库直接分配对外内存,然后通过一块存储在java队中的DirectByteBuffer对象作为这块直接内存的引用直接进行操作,这样避免了java对和Native堆也就是直接内存来回复制数据

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

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,160评论 11 349
  • 一:java概述: 1,JDK:Java Development Kit,java的开发和运行环境,java的开发...
    慕容小伟阅读 1,762评论 0 10
  • 隐瞒与说谎都是痛苦的, 要隐瞒就不得不说谎掩饰, 说一句谎就要用十句谎来掩饰, 谎说多了自然就离败露不远了。 我不...
    辛若有心阅读 320评论 0 1
  • 有时候匆匆的奔走人就是达不到理想的效果,也就是说心里不满意,什么也就失去了意义。既然做得不够称心如意那就应当开始无...
    新人素阅读 151评论 0 1
  • 今天的主题是“15天销售150万案例”! 这个案例是揽客魔创始人郑传华前段时间帮某袜业集团策划的一次营销活动,现在...
    大号运营那些事阅读 372评论 0 1