JVM基础 - Java内存区域

一、Java内存区域

1.运行时数据区域

运行时数据区域.png

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。
有些区域是线程私有的,有些区域是线程共享的。

1)线程私有

  • Java虚拟机栈
  • 本地方法栈
  • 程序计数器

2)线程共享

  • 方法区
  • 运行时常量池
  • 直接内存

2.Java虚拟机栈

1)什么是栈?

先进后出(FILO)的数据结构,可以想象一下弹夹的原理,子弹先压入的会最后打出。

2)什么是Java虚拟机栈?

存储当前线程运行Java方法的数据、指令和返回地址。

3)Java虚拟机栈中存储内容?

虚拟机栈的核心是栈帧,随着方法的调用和返回,在Java虚拟机栈中对应的是栈帧的入栈和出栈。栈帧中存储了这个方法的全部信息(局部变量表、操作数栈等)。

4)Java虚拟机栈参数

虚拟机栈的大小缺省为 1M,可用参数 –Xss 调整大小,例如-Xss256k。
参数官方文档(JDK1.8):https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

5)栈帧的数据结构

屏栈帧的数据结构.png

方法执行伴随着Java虚拟机栈中压入了一个栈帧,字节码指令执行依赖于栈帧中的内容。

i)局部变量表

局部变量的表,存放局部变量。存储单元32bit的长度,主要存放Java的8大基础数据类型,所以一般32bit就可以存放,long和double使用高低位占用两个也可以存放下。
局部的对象只需要存放它的引用地址。

ii)操作数栈

操作数栈存放Java方法执行的操作数,数据结构是一个栈,操作的元素可以是任意的Java数据类型。一个方法刚开始时,操作数栈是空的。

操作数栈是执行引擎的一个工作区,线程在执行方法时才会对操作数栈进行操作,如果不执行代码则操作数栈是空的。

冯诺伊曼结构:CPU + 内存 + 磁盘
操作系统也是一个个软件,运行时主要操作 CPU + 缓存 + 主内存。
JVM和操作系统类似,是一个Mini版的操作系统,JVM执行引擎数据放在栈和堆中,操作数栈就是JVM的缓存。所以JVM运行时主要操作 执行引擎 + 操作数栈 + 栈和堆。

操作数栈就好比操作系统的高速缓存。

字节码指令集:https://cloud.tencent.com/developer/article/1333540

iii)动态链接

Java语言特性多态

iv)返回地址(完成出口)

正常返回:调用程序计数器中的地址作为返回
异常返回:通过异常处理器表<非栈帧中的>来确定

3.程序计数器

存储空间小,指向当前线程正在执行的字节码指令的地址,各个线程间私有,互不影响。

为什么需要程序计数器?

操作系统时间片轮转,程序计数器确保在执行代码过程中,由于到达时间片时间,线程回归就绪状态,再次得到时间片时还能按照之前的指令行号继续执行。

程序计数器是在JVM中唯一不会发生 OOM 异常的内存区域。

4.本地方法栈

本地方法栈跟Java虚拟机栈的功能类似,Java虚拟机栈用于管理Java函数的调用,而本地方法栈则用于管理本地方法的调用。但本地方法并不是用Java实现的,而是由C语言实现的(比如 Object.hashcode 方法)。
本地方法栈是和虚拟机栈非常相似的一个区域,它服务的对象是native方法。你甚至可以认为虚拟机栈和本地方法栈是同一个区域。虚拟机规范无强制规定,各版本虚拟机自由实现 ,HotSpot直接把本地方法栈和虚拟机栈合二为一。

5.方法区

  • 永久代与元空间
  • 运行时常量池

方法区(Method Area)是可供各条线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池(Runtime Constant Pool) 字段和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法

方法区是JVM对内存的“逻辑划分”,在 JDK1.7 及之前很多开发者都习惯将方法区称为“永久代”,是因为在 HotSpot 虚拟机中,设计人员使用了永久代来实现了JVM 规范的方法区。在JDK1.8及以后使用了元空间来实现方法区。

1)jdk7永久代、jdk8元空间

方法区与堆空间类似,也是一个共享内存区,所以方法区是线程共享的。假如两个线程都试图访问方法区中的同一个类信息,而这个类还没有装入 JVM, 那么此时就只允许一个线程去加载它,另一个线程必须等待。

在 HotSpot 虚拟机、Java7 版本中已经将永久代的静态变量和运行时常量池转移到了堆中,其余部分则存储在 JVM 的非堆内存中,而 Java8 版本 已经将方法区中实现的永久代去掉了,并用元空间(class metadata)代替了之前的永久代,并且元空间的存储位置是本地内存。

2)运行时常量池

运行时常量池(Runtime Constant Pool)是每一个类或接口的常量池(Constant_Pool)的运行时表示形式,它包括了若干种不同的常量:从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段引用。

运行时常量池是方法区的一部分。运行时常量池相对于 Class 常量池的另外一个重要特征是具备动态性。

符号引用 -变-> 直接引用

5.堆

堆是JVM最大的内存区域,我们申请的几乎所有的对象,都是在这里存储的。我们常说的垃圾回收,操作的对象就是堆。堆空间一般是程序启动时,就申请了,但是并不一定会全部使用。堆一般设置成可伸缩的。随着对象的频繁创建,堆空间占用的越来越多,就需要不定期的对不再使用的对象进行回收。这个在 Java 中,就叫作GC(Garbage Collection)。

那一个对象创建的时候,到底是在堆上分配,还是在栈上分配呢?
这和两个方面有关:对象的类型和在 Java 类中存在的位置。

Java 的对象可以分为基本数据类型和普通对象。对于普通对象来说,JVM 会首先在堆上创建对象,然后在其他地方使用的其实是它的引用。比如,把这个引用保存在虚拟机栈的局部变量表中。 对于基本数据类型来说(byte、short、int、long、float、double、char),有两种情况。 当你在方法体内声明了基本数据类型的对象,它就会在栈上直接分配。其他情况,都是在堆上分配

5.直接内存

直接内存有一种更加科学的叫法,堆外内存。
JVM 在运行时,会从操作系统申请大块的堆内存,进行数据的存储;同时还有虚拟机栈、本地方法栈和程序计数器,这块称之为栈区。操作系统剩余的内存也就是堆外内存。它不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域;

如果使用了NIO,这块区域会被频繁使用,在 java 堆内可以用 directByteBuffer 对象直接引用并操作;

这块内存不受 java 堆大小限制,但受本机总内存的限制,可以通过-XX:MaxDirectMemorySize 来设置(默认与堆内存最大值一样),所以也会出现 OOM 异常。

2)内存小结:

  1. 直接内存主要是通过 DirectByteBuffer 申请的内存,可以使用参数“MaxDirectMemorySize”来限制它的大小。
  2. 其他堆外内存,主要是指使用了 Unsafe 或者其他 JNI 手段直接直接申请的内存。 堆外内存的泄漏是非常严重的,它的排查难度高、影响大,甚至会造成主机的死亡。

同时,要注意 Oracle 之前计划在 Java 9 中去掉 sun.misc.Unsafe API。这里删除 sun.misc.Unsafe 的原因之一是使 Java 更加安全,并且有替代方案。目前我们主要针对的 JDK1.8,JDK1.9暂时不放入讨论范围中,我们大致知道java的发展即可。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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