薄情先生|程序员进阶系列:多图教你掌握JVM( 二 )


薄情先生|程序员进阶系列:多图教你掌握JVM如上图所示 , 按照内存共享来划分 JVM 内存 , 主要划分为线程共享内存区域(堆、方法区)、线程私有内存区域(程序计数器、虚拟机栈、本地方法栈)、直接内存 。
JVM 运行时数据区解剖从上面介绍 , 可以清晰知道 JVM 运行时数据区 , 主要分为程序计数器、虚拟机栈、本地方法栈、方法区、堆 。 接下来就逐步解剖 , 简单了解一下 。

  • 程序计数器
程序计数器(PC Register) , 也有人称它为 PC 寄存器 。
主要是为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置 , 每个线程都需要有自己独立的程序计数器 。
  • 虚拟机栈
虚拟机栈(VM Stack) , 也有人称它为 Java 虚拟机栈、栈或者 JVM 栈 , 这块就是大家经常分析一段程序执行时要关注的区域 。
JVM 栈是每个线程私有的 , 线程创建的同时都会创建对应的 JVM 栈 。
JVM 栈中存放的是当前线程中局部基本类型的变量、返回结果以及 Stack Frame , 而非基本类型的对象在 JVM 栈上仅存放一个指向堆上的地址 。
  • 本地方法栈
本地方法栈(Native Method Stack)与 JVM 栈很相似 , 本地方法栈也是每个线程私有的 , 只不过是服务的对象不同 , JVM 栈是为执行 Java 方法服务 , 而本地方法栈则是为执行本地方法(Native Method)服务 。
  • 方法区
方法区(Method Area) , 也有人称它为永久代 , 是线程共享的区域 。
在方法区中 , 主要存放静态变量、常量、类信息、运行时常量池以及所有的方法的信息 。 运行时常量池(Runtime Constant Pool)是方法区的重要一部分 , 用于存储编译器生成的常量和引用 。
薄情先生|程序员进阶系列:多图教你掌握JVM(JDK 1.8 内存模型)
如上图所示 , 值得注意的是 JDK 1.8 相比 JDK 1.7 , JVM 运行时数据区划分中的方法区(持久代)从 JVM 运行时数据区拿掉了 , 而在本地内存加入了元数据区(Metadata Memory) , 简而言之在 JDK 1.8 中 , 元数据区替代了方法区(持久代) 。
堆(Heap) , 所有 new 出来的对象实例都存储在该区域 , 这块区域也是线程共享的 , 也是分析 Java 程序时关注较多的一块 。
  • 其它
直接内存(Direct Memory) , 有时也称作堆外内存 , 是不受 JVM控制的内存 。
在 JDK 1.4 中加入了 NIO , 引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式 , 它可以使用 Native 函数库直接分配堆外内存 , 然后通过一个存储在 Java 堆里面的DirectByteBuffer 对象作为这块内存的引用进行操作 。
避免了在 Java 堆和 Native 堆中来回复制数据 , 能在一些场景中显著提高性能 。
寄语写最后本次 , 主要让大家了解一下 JVM 的内存结构 , 希望通过本次分享 , 大家对 JVM 能有个梗概的认识 , 想要彻底掌握还需针对性的弥补 , 说句心里话 , 希望能够把这些图都记在脑子里 , 只要做到脑中有图 , 心就不慌 。
好了 , 本次就谈到这里 , 一起聊技术、谈业务、喷架构 , 少走弯路 , 不踩大坑 。 欢迎关注「一猿小讲」 , 会持续输出原创精彩分享 , 敬请期待!
历史原创推荐程序员进阶系列:你真的懂 HelloWorld 吗?
程序员进阶系列:年少不懂爱家家 , 懂了已是猿中人
Java线程池深度揭秘
Java 8 的这些特性 , 你知道吗?
Java程序跑的快 , 全要靠线程带


推荐阅读