当前位置: 首页 > news >正文

JVM内存结构和各种结构的作用

文章目录

  • 前言
  • 方法区(Method Area)
    • 功能
    • 示例
    • 存储内容
    • 方法区与永久代和元空间三者的关系
  • 堆(Heap)
    • 功能
    • 示例
  • 虚拟机栈(JVM Stacks)
    • 功能
    • 示例
    • 栈帧结构
  • 程序计数器(PC Register)
    • 功能
    • 示例
  • 本地方法栈(Native Method Stacks)
    • 功能
    • 示例
  • 直接内存
    • 功能
    • 示例


在这里插入图片描述

前言

对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像 C/C++程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。

JVM(Java Virtual Machine)的内存结构是 Java 程序运行的基础,JVM的内存结构主要分为程序计数器、虚拟机栈、本地方法栈、堆、方法区等区域,每个部分承担着不同的功能和角色。
在这里插入图片描述
其中线程私有的有:程序计数器、虚拟机栈、本地方法栈
其中线程共享的有:堆、方法区、直接内存 (非运行时数据区的一部分)

方法区(Method Area)

功能

  • 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它是各个线程共享的内存区域。比如,类的字段、方法信息,以及运行时常量池(包含字符串常量等)都存放在这里。
  • 1.8之前的版本中,方法区用永久代来进行实现,永久代中包含类信息、类加载器、运行时常量池。
  • 1.8之后永久代被废弃,变为在元空间中,元空间在本地内存(操作系统的内存)中。

示例

定义一个 public class MyClass { static int num = 10; },其中 num 这个静态变量就存储在方法区。

存储内容

  • 类信息:包括类的全限定名、父类信息、接口信息、字段信息、方法信息等。
  • 常量池:运行时常量池是方法区的一部分,用于存储编译期生成的各种字面量和符号引用。例如,字符串常量、基本数据类型的常量等。
  • 静态变量:类的静态变量在类加载时被分配到方法区,所有该类的实例共享这些静态变量。
  • 即时编译器编译后的代码:JVM 会在运行时对热点代码进行即时编译,编译后的机器码也会存储在方法区。

方法区与永久代和元空间三者的关系

永久代以及元空间是 HotSpot 虚拟机对虚拟机规范中方法区的两种实现方式。并且,永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。
在这里插入图片描述

堆(Heap)

功能

  • 堆是 Java 虚拟机所管理的内存中最大的一块,几乎所有的对象实例以及数组都在堆上分配内存,是被所有线程共享的区域。
  • 它是垃圾回收(GC)的主要工作区域(也被称为 “GC 堆”)。
  • 堆的主要作用是为对象提供存储空间,使得 Java 程序可以动态地创建和管理对象。
  • 堆分为新生代和老年代等不同区域,新生代又细分为 Eden 区、Survivor 0 区和 Survivor 1 区。
    • 新生代(Young Generation):新创建的对象通常会被分配到新生代。
      • 新生代又可细分为一个 Eden 区和两个 Survivor 区(Survivor 0 和 Survivor 1,也称为 From 区和 To 区)。
      • 大多数对象在创建后很快就不再使用,因此新生代的垃圾回收较为频繁,采用的是复制算法
      • 当对象首次创建时,会被分配到 Eden 区,当 Eden 区满时,会触发一次 Minor GC,存活的对象会被复制到其中一个 Survivor 区,同时清空 Eden 区。经过多次 Minor GC 后仍然存活的对象会被晋升到老年代
    • 老年代(Old Generation):用于存放经过多次垃圾回收仍然存活的对象,或者是大对象(直接分配到老年代的对象)。老年代的垃圾回收通常称为 Major GC 或 Full GC,频率相对较低,但回收的时间通常较长,采用的是标记 - 清除或标记 - 整理算法。
    • 永久代(Permanent Generation,Java 8 之前)/ 元空间(Metaspace,Java 8 及以后):
    • 在 Java 8 之前,永久代用于存储类的元数据、常量池等信息,它是堆的一部分,有固定的大小限制,容易出现永久代溢出(OutOfMemoryError: PermGen space)的问题。
    • 从 Java 8 开始,永久代被元空间取代,元空间使用本地内存,不再受堆内存大小的限制,减少了永久代溢出的风险。

示例

Object obj = new Object(); 语句创建的 obj 对象就存放在堆中。

虚拟机栈(JVM Stacks)

功能

  • 每个 Java 线程都有自己的虚拟机栈,它描述的是 Java 方法执行的内存模型。虚拟机栈是线程私有的,它的生命周期与线程相同。
  • 每个方法在执行的同时会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
  • 方法调用的过程就是栈帧在虚拟机栈中入栈和出栈的过程。虚拟机栈为 Java 方法的执行提供了内存支持,保证了方法的正确调用和返回。

示例

现在有一个 public void methodA() { int i = 10; } 方法,当调用 methodA 时,会在虚拟机栈中为其创建栈帧,i 作为局部变量存储在该栈帧的局部变量表中。

栈帧结构

虚拟机栈由一个个栈帧(Stack Frame)组成,每个栈帧对应一个正在执行的方法。栈帧主要包含以下几个部分:

  • 局部变量表:用于存储方法的局部变量,包括基本数据类型和对象引用。局部变量表的大小在编译时就已经确定。
  • 操作数栈:是一个后进先出(LIFO)的栈,用于在方法执行过程中进行数据的计算和操作。例如,在执行算术运算时,操作数会被压入操作数栈,计算结果也会从操作数栈中弹出。
  • 动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,用于支持方法调用的动态链接。在方法调用时,通过动态链接可以将符号引用转换为直接引用。
  • 方法出口(方法返回地址):记录了方法执行完毕后返回的地址,以便线程能够返回到调用该方法的位置继续执行。

程序计数器(PC Register)

功能

  • 可以看作是当前线程所执行的字节码的行号指示器。
  • 字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
  • 如果线程正在执行的是一个 Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
  • 如果正在执行的是 Native 方法,这个计数器值则为空(Undefined)。
  • 它是线程私有的内存区域。

示例

在 Java 程序执行过程中,字节码解释器依据程序计数器的值来获取下一条要执行的指令,如执行 i++ 这样的指令时,程序计数器会记录执行的位置。

本地方法栈(Native Method Stacks)

功能

  • 与虚拟机栈所发挥的作用类似,不过虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。同样是线程私有的。
  • 本地方法栈为本地方法的执行提供了内存支持,使得 Java 程序能够调用本地方法,与底层系统进行交互。

示例

当 Java 程序通过 JNI(Java Native Interface) 调用本地 C/C++ 方法时,相关的调用信息等就存储在本地方法栈中。

直接内存

功能

  • 不受 JVM 内存回收管理,为系统内存
  • 分配是在堆外进行的,减少堆内存的压力
  • 分配回收成本较高,但读写性能高

示例

ByteBuffer.allocateDirect()


相关文章:

  • 蓝桥备赛(11)- 数据结构、算法与STL
  • VMware虚拟机中CentOS8系统账户,忘记密码怎么找回
  • [内网安全] Windows 域认证 — Kerberos 协议认证
  • Objective-C 中 @synthesize VS @dynamic
  • 每日一题——缺失的第一个正数
  • Taro React组件开发 —— RuiNoticeBar 通知栏
  • K8S高可用集群-小白学习之二进制部署(ansible+shell)
  • T31ZC 君正SOC芯片 应用于智能家居、工业控制等 满足各种嵌入式应用的需求 提供样品测试+软硬件资料
  • docker-compose安装redis-主从+哨兵(3台虚拟机一主两从)
  • 深度学习模型组件-RevNorm-可逆归一化(Reversible Normalization)
  • 行为模式---迭代器模式
  • MySQL 主主复制与 Redis 环境安装部署
  • 开发模型与测试模型
  • 原码、反码和补码的介绍和区别
  • pycharm找不到conda可执行文件
  • 系统架构设计师—数据库基础篇—数据库的控制功能
  • 【形态学操作中的开运算和闭运算详细讲解】
  • Windows设置目录及子目录大小写不敏感暨git克隆报错同名文件已存在的解决办法
  • Flink MysqlCDC和OracleCDC对比
  • 虚拟卡 WildCard (野卡) 保姆级开卡教程
  • 保定网站推广费用/爱站网 关键词挖掘工具
  • 亚马逊做品牌备案自有网站/网站如何快速推广
  • 网页微信怎么登陆/黑帽seo是什么
  • 专业制作网站/代刷网站推广链接0元价格
  • 优惠券网站要怎么做/成都seo服务
  • 网站仿造/公司网站推广怎么做