笔记 -- JVM内存结构

  • Java虚拟机(Java Virtual Machine,简称JVM),Java的“一处编译,处处运行”,就是因为Java程序编译成字节码文件后可以在任何计算机的JVM上执行,所以JVM是我们学习Java的重点之一。
  • JVM = 类加载器(classloader) + 执行引擎(execution engine) + 运行时数据区域(runtime data area)。
    在这里插入图片描述
  • 下面我们从每个区域的用途,涉及的问题等方面来简单的说一说JVM的内存结构。

方法区

  • 作用:用于存放已被加载的类信息、常量、静态变量、即时编译器(JIT)编译后的代码等数据。
  • 所有线程共享方法区。
  • 方法区内存可以动态扩展,动态扩展失败会抛出 OutOfMemoryError 异常。
  • 运行时常量池:是方法区的一部分。
    • 作用:Class 文件中的常量池(编译器生成的各种字面量和符号引用),会在类加载后被放入这个区域。
  • 在jdk1.6之前,方法区是通过永久代的方式实现的,此时运行时常量池中有字符串常量池。而通过逐步调整,在jdk1.8之后方法区改为通过元空间实现且挪到了本地内存,而字符串常量池挪到了Java堆中。
    jdk1.6
    jdk1.8

Java堆

  • 作用:存放对象实例,几乎所有的对象实例都存放在这里。
  • 所有线程共享Java堆。
  • Java堆是垃圾收集器管理的主要区域,因此Java堆很多时候也被叫做 "GC"堆
  • Java堆内存可以动态扩展,动态扩展失败会抛出 OutOfMemoryError 异常。

虚拟机栈

  • 定义:每个线程运行所需要的内存空间,称为虚拟机栈。
  • 作用:一个线程每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
    • 局部变量表:存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型)。其中64位长度的long和double类型的数据会占用2个局部变量空间,其余的数据类型只占用1个
    • 操作栈:当一个方法刚刚开始执行时,其操作栈为空,随着方法执行和字节码指令的执行,JVM会从局部变量表或对象实例的字段中复制常量或变量写入到操作栈,再随着程序的进行将栈中元素出栈到局部变量表或者返回给方法调用者。简单理解,操作栈就是线程的控制台。
    • 动态链接:class文件中是通过符号引用来表示一个方法调用了其他方法或者访问其成员变量的。动态链接的作用就是将这些符号引用多表示的方法转换成实际方法的直接引用。
    • 方法出口:方法返回地址。
  • 一个线程对应一个虚拟机栈,所以虚拟机栈是线程私有的。
  • 当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。

程序计数器

  • 作用:保存当前执行指令的地址,一旦指令执行,程序计数器将更新到下一条指令。
  • 程序计数器是线程私有的。
  • 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie方法,这个计数器值则为空(undefined)。

本地方法栈

*本地方法栈与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。

  • 本地方法栈是线程私有的。
  • 与虚拟机栈一样,本地方法栈区域也会抛出 StackOverflowErrorOutOfMemoryError 异常。

猜你喜欢

转载自blog.csdn.net/weixin_44653914/article/details/105443256
今日推荐