讲讲 JVM 的内存结构(附上Demo讲解)

news2024/11/15 22:27:01

讲讲 JVM 的内存结构

  • 什么是 JVM 内存结构?
    • 线程私有
      • 程序计数器​
      • 虚拟机栈
      • 本地方法栈
    • 线程共享
      • 堆​
      • 方法区​
      • 注意
        • 永久代​
        • 元空间​
        • 运行时常量池​
        • 直接内存​
  • 代码详解

什么是 JVM 内存结构?

在这里插入图片描述

JVM内存结构分为5大区域,程序计数器、虚拟机栈、本地方法栈、堆、方法区。​

HotSpot在JDK1.8之前方法区就是永久代,永久代就是方法区。JDK1.8后删除了永久代,改为元空间,元空间在本地内存中。方法区就是元空间,元空间就是方法区。​

创建一个线程,JVM就会为其分配一个私有内存空间,其中包括PC、虚拟机栈和本地方法栈​

简单来说:

  • 堆:存放 new 出来的东西
  • 方法区:被虚拟机加载的类信息、常量、静态常量等。
  • 栈:存放局部变量
  • 程序计数器:记录指令
  • 本地方法栈:Native 方法

接着进行详细的介绍:

线程私有

程序计数器​

线程私有的,作为当前线程的行号指示器,用于记录当前虚拟机正在执行的线程指令地址。程序计数器主要有两个作用:​

  • 当前线程所执行的字节码的行号指示器,通过它实现代码的流程控制,如:顺序执行、选择、循环、异常处理。​
  • 多线程的情况下,程序计数器用于记录当前线程执行的位置,当线程被切换回来的时候能够知道它上次执行的位置。​

程序计数器是唯一一个不会出现 OutOfMemoryError 的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。​

虚拟机栈

Java 虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。每一次函数调用都会有一个对应的栈帧被压入虚拟机栈,每一个函数调用结束后,都会有一个栈帧被弹出。​

局部变量表是用于存放方法参数和方法内的局部变量。​

每个栈帧都包含一个指向运行时常量池中该栈所属方法的符号引用,在方法调用过程中,会进行动态链接,将这个符号引用转化为直接引用。​

  • 部分符号引用在类加载阶段的时候就转化为直接引用,这种转化就是静态链接​
  • 部分符号引用在运行期间转化为直接引用,这种转化就是动态链接​

Java 虚拟机栈也是线程私有的,每个线程都有各自的 Java 虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。

Java 虚拟机栈会出现两种错误:StackOverFlowErrorOutOfMemoryError。​
可以通过 -Xss 参数来指定每个线程的虚拟机栈内存大小:java -Xss2M​

本地方法栈

虚拟机栈为虚拟机执行 Java 方法服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。Native 方法一般是用其它语言(C、C++等)编写的。​

本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。​

线程共享

堆​

堆用于存放对象实例,是垃圾收集器管理的主要区域,因此也被称作GC堆。​

堆可以细分为:新生代(Eden空间(伊甸园)、From Survivor、To Survivor空间)和老年代。​

通过 -Xms 设定程序启动时占用内存大小,通过 -Xmx 设定程序运行期间最大可占用的内存大小。如果程序运行需要占用更多的内存,超出了这个设置值,就会抛出OutOfMemory异常。​

方法区​

方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。​

对方法区进行垃圾回收的主要目标是对常量池的回收和对类的卸载。​

注意

永久代​

方法区是 JVM 的规范,而永久代PermGen 是方法区的一种实现方式,并且只有 HotSpot 有永久代。对于其他类型的虚拟机,如 JRockit 没有永久代。由于方法区主要存储类的相关信息,所以对于动态生成类的场景比较容易出现永久代的内存溢出。​

元空间​

JDK 1.8 的时候,HotSpot的永久代被彻底移除了,使用元空间替代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。

两者最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

为什么要将永久代替换为元空间呢?​
永久代内存受限于 JVM 可用内存,而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是相比永久代内存溢出的概率更小。​

运行时常量池​

运行时常量池是方法区的一部分,在类加载之后,会将编译器生成的各种字面量和符号引号放到运行时常量池。在运行期间动态生成的常量,如 String 类的 intern()方法,也会被放入运行时常量池。​

直接内存​

直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致 OutOfMemoryError 错误出现。​

NIO 的 Buffer 提供了 DirectBuffer,可以直接访问系统物理内存,避免堆内内存到堆外内存的数据拷贝操作,提高效率。

DirectBuffer直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制,不受最大堆内存的限制。​

直接内存的读写操作比堆内存快,可以提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到直接内存。

在这里插入图片描述

代码详解

以下是一个简单的 Java 类,我们将在注释中说明各个内存区域的作用:

public class MemoryStructureExample {
    // 静态变量,存放在方法区
    private static int staticVar = 42;

    public static void main(String[] args) {
        // 局部变量,存放在虚拟机栈
        int localVar = 10;

        // 创建一个对象,存放在堆中
        MemoryStructureExample obj = new MemoryStructureExample();

        // 调用方法,创建一个新的栈帧
        obj.doSomething(localVar);

        // 创建一个数组,存放在堆中
        int[] array = new int[5];

        // 常量,存放在方法区
        final String constantString = "Hello, world!";

        // 本地方法调用,使用本地方法栈
        System.out.println("Static variable: " + staticVar);
        System.out.println("Constant string: " + constantString);
    }

    // 方法,存放在方法区
    public void doSomething(int value) {
        // 局部变量,存放在虚拟机栈
        int result = value * 2;
        System.out.println("Result: " + result);
    }
}

在这段代码中,我们可以看到:

  • staticVar 是一个静态变量,存放在方法区。
  • localVar 是一个局部变量,存放在虚拟机栈。
  • obj 是一个对象,存放在堆中。
  • array 是一个数组,也存放在堆中。
  • constantString 是一个常量,存放在方法区。
  • doSomething 方法创建了一个新的栈帧,其中的局部变量存放在虚拟机栈。

总之,这些内存区域共同构成了 Java 虚拟机的内存结构,确保 Java 程序的正常运行和优化。如果你还有其他问题,欢迎继续提问!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

50、haproxy+keepalive+nginx

keepalivehaproxy 客户端:192.168.168.21haproxy1:192.168.168.43haproxy2:192.168.168.44vip:192.168.168.100nginx1:192.168.168.31nginx2:192.168.168.32haproxykeepalive做高可用nginx做后台haproxy1haproxy2一起操作&#x…

实验发现AI提高了个人创造力,但降低了整体创造力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

从链表中移除在数组中存在的节点 | 力扣题解

⭐简单说两句⭐ ✨ 正在努力的小叮当~ 💖 超级爱分享,分享各种有趣干货! 👩‍💻 提供:模拟面试 | 简历诊断 | 独家简历模板 🌈 感谢关注,关注了你就是我的超级粉丝啦! &a…

【自监督学习】iBOT in ICLR 2022

一、引言 论文: iBOT🤖: Image BERT Pre-Training with Online Tokenizer 作者: ByteDance 代码: iBOT 注意: 该方法是在另一个自监督预训练方法基础上的改进,学习之前建议掌握DINO。 特点: 对…

数据结构之初始二叉树(1)

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:数据结构(Java版) 目录 树型结构 树的概念 与树的有关概念 树的表示形式 树的应用 二叉树 概念 两种特殊的…

MFC流的形式读取图片

1.基于对话框布置控件 2.给控件绑定变量 3.给按钮控件添加响应函数 void CMFC流的形式读取图片Dlg::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码//HDC mECGDC; // 设备描述表句柄//CPen mECGDrawPen; // ECG波形画笔//RECT mECGRect; // 在该矩形区域内画…

Three.js相机简明教程

相机校准是 3D 计算机图形学中的一个基本概念,涉及设置虚拟相机以模拟真实世界相机的视角和行为。在 Three.js(一种流行的 3D 渲染 JavaScript 库)中,了解相机校准对于创建逼真且身临其境的 3D 场景至关重要。在本文中&#xff0c…

AIGC是什么,与AI绘画有什么关系,一篇文章带你了解AI绘画的前世今生

在讲解AIGC和AI绘画之前,我们先看看什么是AI以及AI的历史。 AI历史发展轨迹 什么是人工智能 人工智能(Artificial intelligence,简称AI)亦称机器智能,指由人制造出来的机器所表现出来的智能。通常人工智能是指用普通计算机程序来呈现人类智…

ConfigMap-secrets-静态pod

一.ConfigMap 1.概述 ConfigMap资源,简称CM资源,它生成的键值对数据,存储在ETCD数据库中 应用场景:主要是对应用程序的配置 pod通过env变量引入ConfigMap,或者通过数据卷挂载volume的方式引入ConfigMap资源 官方解释…

成为git砖家(1): author 和 committer 的区别

大家好,我是白鱼。一直对 git author 和 committer 不太了解, 今天通过 cherry-pick 的例子搞清楚了区别。 原理 例如我克隆了著名开源项目 spdlog 的源码, 根据某个历史 commit A 创建了分支, 然后 cherry-pick 了这个 commit …

240710_昇思学习打卡-Day22-条件随机场

240710_昇思学习打卡-Day22-条件随机场 在正式开始LSTMCRF序列标注之前,我们先来了解一下条件随机场,以下仅做简单介绍。 CRF全称Conditional Random Field,按照名字来理解,条件随机,随机输入,条件输出。…

vue中父子传递属性值

1、父传子属性值 自定义图库组件 在add.vue中应用tuku组件并给默认值 效果 2、 子传父,逆向赋值 add.vue和第一问中一样 修改tuku组件,传值给add.vue 3、多个传递 效果: 点击两个修改按钮后 4、使用defineModel简化父子传值 其他代码跟…

使用Tkinter库设计实现的中小学校疫情防控入校人员登记检测系统

Tkinter简介 Tkinter是Python标准库中用于GUI图形用户界面开发的工具包,它是基于Tcl/Tk的封装,提供了大量预定义的控件,如按钮、文本框、标签等,非常适合快速原型开发和小型应用的构建。本文将通过一个具体的案例——“中小学校疫…

【java】力扣 合并k个升序链表

文章目录 题目链接题目描述思路代码 题目链接 23.合并k个升序链表 题目描述 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表 思路 我在这个题里面用到了PriorityQueue(优先队列) 的知识 Prio…

鸿蒙语言基础类库:【@system.app (应用上下文)】

应用上下文 说明: 从API Version 7 开始,该接口不再维护,推荐使用新接口。本模块首批接口从API version 3开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 import app from system.app;app.getInfo …

MFC之对话框--重绘元文件

文章目录 实现示例展示需要绘制的窗口/位置控件位置更新下一次示例粗细滑动部分更新 重绘元文件(窗口变化内容消失)方法一:使用元文件方法二:兼容设备方法三:使用自定义类存储绘图数据除画笔外功能处理画笔功能处理 保…

【雷达原理】MIMO雷达技术

一、MIMO雷达原理 1.1 基本概念 多输入多输出(Multiple input multiple output,MIMO)雷达指该雷达具有多个发射天线和多个接收天线。 学术界对 MIMO 雷达的定义中,多输入是指同时发射多种雷达信号波形( 一般是多个天线同时发射不同的波形) ,…

藏着不为人知的泪水

在娱乐圈的璀璨舞台上,每一个光芒四射的背后,藏着不为人知的汗水与泪水。提及#张艺凡 出道位#,这段历程,不仅仅是个人奋斗的见证,更是关于勇气、坚持与自我证明的壮丽篇章。曾几何时,网络的喧嚣声中&#x…

【信息系统项目管理师】高项常见知识点与公式

绩效域、合同、配置、变更、招投标、安全、立项论文考到的话大致业是按下面相关知识点开写 八大绩效域及其要点 团干部策划开公交 合同管理 合同的签订->合同的履行管理->合同的变更管理->合同的档案管理->合同的违约\索赔管理 配置管理 制定配置管理计划配置识…

欧几里得算法求解若干数的最小公倍数

公倍数 公倍数(common multiple)是指在两个或两个以上的自然数中,如果它们有相同的倍数,这些倍数就是它们的公倍数。公倍数中最小的数,就称为这些整数的最小公倍数(lowest common multiple) 求解方法 求多个数的最小公…