JVM内存结构-总纲


[原创]个人理解,请批判接受,有误请指正。转载请注明出处: https://heyfl.gitee.io/JVM/JVM-Memory-Structure-Menu.html

学习JVM的可以去我的GitHub 上查看我的Xmind详细笔记 对整本《深入理解JVM》都有详尽的笔记,帮助理解

前言

网上有不少描述JVM内存结构的文章,但是要么比较老久了,要么描述有误,今天根据自己的理解整理下,有误请指正。

整体图解

JVM内存区域


程序计数器

记录Java程序运行到哪里

  1. 线程私有,可以看做当前线程执行到哪行【字节码】
  2. 字节码解析器工作就是通过改变这个【计数器】来选择下一行要执行什么,分支、循环、线程恢复都依赖于它
    • 若为Java方法,则记录当前执行的字节码指令地址;
    • 若执行的是native方法,则为空

Java 虚拟机栈

  • 描述java【方法】执行的【内存模型】
  • 每个方法对应一个栈帧,在线程运行到该方法时才创建
  • 一条线程拥有的栈帧之和最大为-Xss(我们这里把它叫做线程栈)
  • 当前所有线程栈之和=当前Java虚拟机栈已用大小
  • Java虚拟机栈总空间最大值:JVM 可分配内存-堆最大值-其他空间最大值–>剩下的作为栈的总空间最大值

详细可参考:


本地方法栈

同虚拟机栈,区别在于:虚拟机栈服务于Java方法(字节码),本地方法栈服务于Native方法


  1. 随JVM启动而创建,是虚拟机最大的一块内存,被所有线程共享
  2. 存放着对象与数组等一切new出来的对象
  3. 垃圾收集器主要管理的区域
  4. 还存放着常量池
    (1.7及以后的版本,都移到堆里存储了,需要注意的地方比较多 后面会说 不在这里描述)

详细可参考我另外的这篇博客(待填坑)


字符串常量池

存放字符串常量池,不同JDK版本存放的内容不一样

**1. 怎样的String会被存到常量池

简单来说以下这些情况都会存入常量池:

2. 存储结构在不同JDK下的区别
3. String 加载进字符串常量池的方式/时机

首先要知道字符串常量池是位于运行时常量池中的

  • 编译完刚启动: 加载String进字符串常量池的过程大致为:
          graph LR
      A[编译后的class文件中的class常量池]
      B[运行时常量池中的字符串常量池]
       A-->B;
  • 运行期间
      graph LR
      A[代码]
      B[运行时常量池中的字符串常量池]
       A-->B;

方法区(永久代)

存放类的结构:版本、常量、全局变量、静态变量、方法、接口、即JIT编译后的代码等信息(JDK8后完全移出方法区 可以参考:Java 8: From PermGen to Metaspace)


(不在JVM里的)元数据区

JDK8开始,替代方法区的存在;很大程度的避免了因为类加载过多导致的OOM问题

  • 实际上元数据区不属于JVM内存的一部分;其为本地内存的一部分;大小取决于开发人员配置或可用的本地内存大小
  • 有一点必须注意的是:
    • -XX:MetaspaceSize=128m 不是初始元空间大小,而是达到了128m后才会对该区域进行GC 初始化大小20.8m 默认MetaspaceSize也是20.8m
作者

神奇宝贝大师

发布于

2019-02-16

更新于

2019-02-18

许可协议

评论