目录

  • 定义和说明
    • JVM内存区域的定义
    • 内存区域说明
    • 堆说明
    • 非堆-方法区说明
    • 堆栈的区别
    • HotSpot虚拟机
  • JVM线程独占内存
    • 程序计数器:Program Counter Register
    • Java虚拟机栈:Java Virtual Machine Stack
    • 本地方法栈:Native Method Stack
  • JVM共享内存
    • Java堆:Java Heap
    • 方法区:Method Area
      • 常量池表:Constant Pool Table
      • 运行时常量池:Run-Time Constant Pool
  • 参考

定义和说明

JVM内存区域的定义

JVM(Java Virtual Machine,JavaVM,Java虚拟机),定义了不同的运行时数据区域(run-time data area),一部分区域随JVM启动而创建,随JVM消亡而销毁。其它区域则属于每个线程,随线程启动而创建,随线程关闭而销毁。

内存区域说明

JavaVM的定义,决定其内存将会分为两部分:JVM共享内存、JVM线程独占内存。

  • JVM共享内存分为两部分:堆(Heap)、非堆——方法区(Method Area)
  • JVM线程独占内存分为:虚拟机栈(Java Virtual Machine Stacks)、本地方法栈(Native Method Stacks)、程序计数器(pc Register)

堆说明

堆就是Java代码可及的内存,是留给开发人员使用的,所有类实例和数组的内存均从此处分配。

非堆-方法区说明

  • 非堆就是JVM留给自己用的
  • 这部分的物理内存实际上和堆是连续的,它也是堆的一部分,只是在概念上将其与堆区分开来
  • 方法区实际上只是JVM定义的一个概念,这块区域如何实现取决于具体的虚拟机实例。
  • HotSpot虚拟机在JDK7之前就用永久代实现方法区的功能定义,在JDK8弃用了永久代并使用元空间(metaspace)实现方法区。

堆栈的区别

  • 堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
  • 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据

HotSpot虚拟机

  • 大家使用的主流JDK主要是OpenJDK和OracleJDK这两个版本,他们的VM实现都是HotSpotVM,所以一般我们提到JVM都是代指HotSpotVM
  • 因此下面的内存结构分析,乃至我后面的所有JVM文章,也都是基于HotSpotVM来的。


JVM线程独占内存

线程私有,生命周期与线程相同。

程序计数器:Program Counter Register

作用:又称pc Register, 是一块较小的内存空间,可以被看作当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器。

对于不同的方法程序计数器分别会记录不同的值:

  • 执行普通方法:那么程序计数器就会记录当前虚拟机执行处的地址(address),当线程切换后方便线程继续不中断的执行该方法。
  • 执行native方法:程序计数器的值为undefined。

此外,Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现,为了线程切换后能恢复到正确的执行位置,每个线程都会拥有一个独立的程序计数器独立存储各自的计数器值。各线程之前计数器互不影响。

Java虚拟机栈:Java Virtual Machine Stack

作用:虚拟机栈描述的是Java方法执行的线程内存模型,在物理内存上不一定是连续的。在任意一个时间点,每个JVM线程都只会执行一个方法的代码,这个方法对于该线程来说就是一个栈帧(Frame)。每个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

  • 用于存储局部变量表、操作数栈、动态连接、方法出口等信息。它可能是对分配的。

栈的注意项

  • 虚拟机栈可以为固定大小、也允许在运行时动态扩展。如果虚拟机栈为固定大小时,它的大小将在创建时自主决定。
  • 每个VM实现都会提供用户可以自行控制的栈初始化大小,在支持动态扩展时还会提供栈的最大值设置。

局部变量表:存放编译期可知的各种Java虚拟机基本数据类型、引用类型和returnAddress类型(指向了一条字节码指令的地址)。这些数据类型在局部变量表中的存储空间以局部变量槽(Slot)表示。除了long和double占用两个槽外,其他都只占一个。局部变量表的内存空间在编译期就完成分配了,且在运行期不会改变;

栈溢出(虚拟机栈和本地方法栈溢出情况相似):

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

  • 如果虚拟机的栈内存允许动态扩展,当扩展栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常。

-Xss | -XX:ThreadStackSize:设置该参数以设置栈容量

本地方法栈:Native Method Stack

作用:本地方法栈与虚拟机栈的作用相似,区别在于本地方法栈是为虚拟机使用到的native方法服务;而虚拟机栈是为执行Java方法(也就是字节码)服务。


JVM共享内存

被所有线程共享的一块区域

Java堆:Java Heap

概览:Java堆是虚拟机管理的内存的最大一块,它是被所有线程共享的一块区域。它是垃圾收集器管理的内存区域,也被称为GC堆(Garbage Collected Heap)。

作用:Java堆所管理的内存区域的作用就是存放对象实例。Java几乎所有的对象实例都在这里分配内存。

堆内存

  • 堆内存大小可以是固定值,也可以根据需要动态扩展,在需要更多内存时自动扩展,并在不需要时自动缩减。
  • 每个VM实现都可能会提供用户可以自行控制的堆初始化大小,并在支持动态扩展时还会提供堆的最大值设置。
  • Java堆可以处于物理上不连续的内存空间中,但在逻辑上他们应该被视为连续的。但对于大对象(典型的如数组对象),多数虚拟机实现出于实现简单、存储高效的考虑,很可能会要求连续的物理内存空间。

堆溢出:当我们不断地创建对象,且大量对象被使用(GC roots到对象可达),那么随着对象数量的增加,总容量触及最大堆的容量限制后,通过full gc 也不法清理内存空间时,就会产生内存溢出异常(OutOfMemoryError)。

OOM信息:java.lang.OutOfMemoryError:Java heap space

-XX:+/-HeapDumpOnOutOfMemoryError:可以让虚拟机在出现内存溢出异常的时候Dump出当前的内存堆转储快照以便进行事后分析

OOM解决:通过dump堆转存快照来分析异常

  • 首先应确认内存中导致OOM的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory
    Overflow)。

  • 内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链,找到泄漏对象是通过怎样的引用路径、与哪些GC Roots相关联,才导致垃圾收集器无法回收它们,根据泄漏对象的类型信息以及它到GC Roots引用链的信息,一般可以比较准确地定位到这些对象创建的位置,进而找出产生内存泄漏的代码的具体位置。

  • 内存溢出,如果OOM对象都是必须存在的,那就应当检查Java虚拟机的堆参数(-Xmx与-Xms)设置,与机器的内存对比,看看是否还有向上调整的空间。再从代码上检查是否存在某些对象生命周期过长、持有状态时间过长、存储结构设计不合理等情况,尽量减少程序运行期的内存消耗。

-Xmx | -XX:MaxHeapSize:设置堆最大容量
-Xms | -XX:InitalHeapSize:设置堆最小容量

方法区:Method Area

概览:方法区实际上是一种概念,与Java堆一样,都是线程共享的内存区域。虽然在逻辑上方法区是Java堆的一个逻辑部分,但是它有一个别名“非堆”Non-Heap,用以于Java堆区分开来。

作用:用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。

方法区内存

  • 方法区内存大小可以是固定值,也可以根据需要动态扩展,在需要更多内存时自动扩展,并在不需要时自动缩减。
  • 每个VM实现都可能会提供用户可以自行控制的方法区初始化大小,并在支持动态扩展时还会提供方法区的最大值设置。
  • 方法区在内存上亦不要求连续。

注意:

  • JDK7之后,HotSpot把放在永久代的字符串常量池、静态变量移至了Java堆中。
  • JDK8之后,完全废弃了永久代的概念,改用元空间(Metaspace)来代替,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。
  • 方法区的内存空间:与Java堆一样,此外它甚至还可以选择不实现垃圾收集(这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载)。

方法区溢出:当方法区要去分配的内存超过最大内存限制时,抛出内存溢出异常(OutOfMemoryError)。

设置方法区大小:
JDK7及前:

  • -XX:PermSize:设置永久代初值
  • -XX:MaxPermSize:设置永久代最大值

JDK8及以后:

  • -XX:MetaspaceSize:元空间初值
  • -XX:MaxMetaspaceSize:元空间最大值
常量池表:Constant Pool Table

概览:它实际上是某个类、接口中的常量集合,任意一个类中,都有会无数常量(例如类名、接口名、方法名都是一个常量),在编译完成后常量池表就固定了,运行时也不会发生改变。它是属于方法区中类型信息的一部分。

作用:类型信息中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池表(Constant Pool Table)。它用于存放编译期生成的各种字面量与符号引用,这些内容将在类加载后放到方法区的运行常量池中。

运行时常量池:Run-Time Constant Pool

概览:运行时常量池实际上是类文件中一个类或接口中的常量池表(constant pool table)的集合展现,是方法区的一部分。JDK7之前常量池都是分配在永久代中,JDK7之后,HotSpot把放在永久代的字符串常量池、静态变量移至了Java堆中。

作用:与常量池表相比,运行时常量池具备动态性,运行期间也可以将新的常量放入池中,比如String的intern()方法。

运行时常量池溢出:它不像常量池表不可变动,运行时常量池在扩展时,需要分配的内存超过方法区限制时,抛出内存溢出异常(OutOfMemoryError)。


参考

深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)周志明
Run-Time Data Areas


【JVM学习笔记】JVM内存区域定义与内存结构相关推荐

  1. jvm学习笔记(1)——java虚拟机内存区域

    一.java内存区域: 1.程序计数器(线程私有): 内存中较小的内存空间,可以当做当前线程所执行字节码的行号指示器.如分支.循环.跳转.异常处理.线程恢复都需要依赖这个计数器完成. 2.java虚拟 ...

  2. JVM学习笔记② JVM运行时数据区域

    JVM所管理的内存将会包括以下几个运行时数据区域: 方法区(Method Area) 方法区是各个线程共享的区域,存放类信息.常量.静态变量.即时编译器编译后的代码等数据.虽然Java虚拟机规范把方法 ...

  3. 【JVM学习笔记】内存回收与内存回收算法 就哪些地方需要回收、什么时候回收、如何回收三个问题进行分析和说明

    目录 一.相关名词解释 垃圾收集常用名词 二.哪些地方需要回收 本地方法栈.虚拟机栈.程序计数器 方法区 Java堆 三.什么时候回收 1. 内存能否被回收 内存中的引用类型 引用计数算法 可达性分析 ...

  4. JVM学习笔记(自用)

    JVM学习笔记(自用) 文章目录 JVM学习笔记(自用) 1.简介 2.程序计数器 3. 虚拟机栈 4. 方法区 5. 直接内存 6. 垃圾回收 Young Collection Young Coll ...

  5. JVM学习笔记(四)------内存调优

    首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提 ...

  6. JVM学习笔记之-对象的实例化,内存布局与访问定位,直接内存(Direct Memory)

    对象的实例化 对象的内存布局 图解 对象的访问定位 句柄访问 好处 reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身 ...

  7. JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT

    JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT 第一章:JVM虚拟机的介绍 1.1虚拟机的分类 虚拟机通常分为两类:系统虚拟机和程序虚机.其中,系统虚拟机是指完全对物理计算机的仿真,而程序虚 ...

  8. JVM学习笔记之GUI监控工具

    目录 背景 jConsole 本地连接:连接本地计算机一个正在运行的JVM进程 远程连接:连接JMX代理 高级连接:使用特殊的URL连接JMX代理 VisualVM 插件安装 连接方式 本地连接:连接 ...

  9. JVM学习笔记(四)

    JVM学习笔记(四) 文章目录 JVM学习笔记(四) 笔记链接 1.GC算法 1.1GC-判断对象是否可回收 1.1.1 引用计数法 1.1.1 可达性分析 1.2GC-回收算法 标记清除法(Mark ...

  10. jvm学习笔记(三)

    jvm学习笔记(三) 文章目录 jvm学习笔记(三) 1.全部笔记链接 2.堆 2.1堆的划分 使用JVM参数查看划分 Hotspot堆内存划分图(JDK8之前) 2.2 GC对堆的回收 GC的种类 ...

最新文章

  1. 如何用python创建一个下载网站-如何写一个python脚本下载文件??
  2. 求解最大字段和的几种方法
  3. idea javafx添加maven_IDEA通过Maven打包JavaFX工程(OpenJFX11)
  4. CSS之【超链接伪类】
  5. [云炬创业基础笔记]第二章创业者测试19
  6. PHP的查找stripos strpos strripos strpos
  7. MATLAB作图方法与技巧(二)
  8. C注释   转换为   C++注释
  9. 大学生经验丨帮助应届生、年轻程序员快速成长的 12 个锦囊妙计!
  10. node mysql gbk_nodejs gb2312、GBK中文乱码解决方法
  11. BZOJ5192[Usaco2018 Feb] New Barns
  12. 方舟代码_源代码丢失的方舟
  13. ARM DS5 项目build后无法找到axf文件
  14. 情感日记:梦里花落知多少--记念我的大学
  15. python程序格式框架的描述错误的是_关于 Python 程序格式框架的描述,以下选项中错误的是(       )...
  16. 一个vector内容赋值给另一个vector
  17. 读后感:麦田守望者--走出软件作坊:三五个人十来条枪 如何成为开发正规军(四十三)
  18. 若依分离版部署遇到的问题
  19. 假设检验,p-value,glm
  20. VBoxManage 命令操作,详细的网络设置命令

热门文章

  1. source bash_profile是干啥的
  2. Docker 如何安全地进入到容器内部
  3. 计算机网络 王道考研2021 第一章 -- 计算机网络组成 / 分类
  4. OpenGL ES 2.0 入门(持续更新)
  5. 二值图像的Euclidean distance map(EDM)特征图计算及其优化
  6. c语言中布尔类型字节数,【C语言】中的布尔类型
  7. xls文件二进制格式
  8. 色彩心理学在网站设计中的运用
  9. 2081.09.22 Kuma(非旋treap)
  10. 你必须要知道的软件测试3个主流方式