• 深入理解JVM 运行时数据区域


    1. 运行时数据区域

    注意JVM运行时数据区域与Java内存模型的区别

    • JVM 运行时数据区域:JVM 所管理的内存划分
    • Java内存模型:屏蔽底层硬件和操作系统的区别,在语言级抽象java的内存访问,使得在不同的环境中java一致的内存访问效果

    image

    2. 程序计数器 Program Counter Register

    当前线程所执行的字节码的行号指示器
    JVM概念模型中,字节码解释器通过改变PC选取下一条要执行的指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个指示器完成。
    线程为OS调度的基本单位,Java的线程模型使用的是内核指称的一对一模型,每个线程都需要有自己的PC,因此PC是线程私有的内存。
    若当前线程正在执行Java方法,则PC为正在执行的虚拟机字节码指令地址;若正在执行本地方法(Native),则值未定义(Undefined)。
    唯一一个未在《JVM规范》中指定OutOfMemoryError的内存区域

    JVM概念模型:有点类似Java内存模型,都是高度的抽象,JVM概念模型则是JVM的抽象,而具体实现不一定根据这个抽象模型实现,但是具有相同的效果/功能。

    3. Java 虚拟机栈 Java Virtual Machine Stack

    线程私有,生命周期与线程相同
    虚拟机栈描述Java方法执行的线程内存模型:一个方法的执行和退出对应一个栈帧(Stack Frame)的入栈和出栈。
    栈帧存放着局部变量表操作数栈动态链接方法出口等信息。
    通常C/C++中描述的堆内存、栈内存中的栈内存就是这里的虚拟机栈,或者是虚拟机栈中的局部变量表部分。

    局部变量表
    存放了编译期可知的各种Java虚拟机基本数据类型(8种)、对象引用(对象指针或句柄指针)和returnAddress(指向一条字节码指令的地址)。
    这些数据在局部变量表的存储空间以局部变量槽(Slot)表示,64位的long和double占用两个变量槽,其余数据类型占用两个。
    局部变量表所需内存空间在编译期完成分配,当进入一个方法时,需要在栈帧中分配多大的局部变量空间是完全确定的。
    虚拟机具体使用多大的内存(32、64位?)实现一个slot取决于具体的实现。

    栈帧
    栈帧中的局部变量表大小编译期确定,那么操作数栈栈是否能完全确定?栈帧需要分配的具体大小是不能确定的吗?按照字节码看,操作数栈需要的空间大小应该也是能在编译期确定的呀?

    异常
    线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError
    如果Java虚拟机栈容量可以动态扩展(取决于具体VM实现,HotSpot不能),当栈扩展时无法申请到足够内存会抛出 OutOfMemoryError
    即便HotSpot的虚拟机栈无法动态扩展,但是当申请一个线程的栈内存时就没有没有足够内存也会抛出 OutOfMemoryError

    4. 本地方法栈 Native Stack

    和虚拟机栈的作用基本相同,为方法服务,不过本地方法栈为本地(Native)方法服务。
    《JVM》为对此内存的实现有限制,HotSpot 将虚拟机栈和本地方法栈合二为一实现。
    异常
    同虚拟机栈,在栈深度溢出和栈扩展失败时分别抛出 StackOverflowErrorOutOfMemoryError

    5. Java 堆 Java Heap

    虚VM所管理内存最大的一块,线程共享,VM启动时创建,唯一目的是创建对象实例,几乎所有实例对象都在这里分配
    即时编译技术的进步,尤其逃逸分析技术的日渐强大,栈上分配、标量替换等优化手段,导致对象可能不在堆中分配。优化后类似C#的struct?
    物理上课不连续,但逻辑上必须连续。
    课实现为可扩展的、也可实现为固定大小的,主流VM均实现为可扩展的。

    异常
    若在Java堆中无法完成实例分配,且堆也无法扩展时,VM将抛出 OutOfMemoryError

    6. 方法区 Method Area

    线程共享、存储已被VM分配的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据
    永久代 Permanent Generation
    方法区在JDK8前的常用称呼,主要是在之前 HotSpot 使用永久代实现方法区,将垃圾收集器的分代设计扩展至方法区,省去单独的内存管理设计。其他虚拟机没有这个称呼。
    JDK7 HotSpot将原永久代的字符串常量、静态变量移出。
    JDK8 Hotspot 废弃永久代,使用元空间(metaspace)实现,将JDK7中永久代剩余内容(主要是类型信息)移到元空间。

    《JVM规范》对方法区限制很宽松,不需要连续物理内存、可选择固定大小或可扩展、可不实现垃圾收集。
    这部分内存回收主要针对常量和类型的卸载。

    异常
    当方法区无法满足新的内存分配需求,将抛出 OutOfMemoryError

    7. 运行时常量池 Runtime Constabnt Pool

    方法区一部分。
    class文件中除了类版本、字段、方法、接口等描述信息,还有常量池表(Constant Pool Table),存放编译期生成的各种字面量与符号引用,这部分在类加载后放到方法区的运行时常量池中
    一般来说,除了保存class文件中的符号引用,也会将由符号引用翻译出来的直接引用也存储在运行时常量池中。

    运行时常量池和class常量池的一个区别是动态性,不要求一定是编译时产生,也可在运行时放入,如 String#intern。

    异常
    方法区一部分,当常量池无法申请到足够内存抛出 OutOfMemoryError

    8. 直接内存 Direct Memory

    非运行时数据区域一部分,非《JVM规范》定义区域。
    DK1.4引入NIO,可使用Native函数库直接分配堆外内存,通过存储在Java堆中的DirectByteBuffer对象引用这块内存,避免Java堆和Native堆中来回复制数据
    异常
    不受Java堆大小限制,但受本地内存限制,申请内存时无足够内存也会抛出 OutOfMemoryError

    9. 扩展概念

    1. CPU的PC
    2. Java内存模型
    3. 基于栈和基于寄存器的虚拟机
    4. 堆和栈的区别
    5. java对象内存布局、引用
    6. 异常级别、全都可以被捕获
    7. String 常量池
    8. 符号引用与直接引用
    9. Java 堆和 Native 堆
  • 相关阅读:
    petshop4.0 详解之三(PetShop数据访问层之消息处理)
    MemberShip的使用
    PetShop 详解之一 系统架构设计
    PetShop4,错误提示:没有为 SQL 缓存通知启用数据库"MyCard"
    PetShop4,错误提示:System.Web.Security.SqlMembershipProvider”要求一个与架构版本“1”兼容的数据
    【Linux从零开始】:1.文件与目录的管理和配置(1)
    【笔记】在.NET中使用强类型有以下优点:
    【好文收藏】:Linq to DataSet
    【好文收藏】泛型与非泛型的比较(百度文库)
    HDOJ1102 Constructing Roads[Prim()]
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/16142197.html
Copyright © 2020-2023  润新知