JVM专题六:JVM的内存模型

news2024/11/27 10:27:04

前面我们通过Java是如何编译、JVM的类加载机制、JVM类加载器与双亲委派机制等内容了解到了如何从我们编写的一个.Java 文件最终加载到JVM里的,今天我们就来剖析一下这个Java的‘中介平台’JVM里面到底长成啥样。

JVM的内存区域划分

Java虚拟机(JVM)是Java程序运行的虚拟计算机,它负责将Java字节码转换为特定平台上的机器指令。JVM的内存区域划分是JVM规范中定义的,它规定了JVM在执行Java程序时所管理的不同内存区域。JVM内存区域的主要划分如下图所示:

方法区&&元空间

        用于存储类信息、常量、静态变量等数据的内存区域。它是所有线程共享的,用于支持类和接口的组织。在HotSpot JVM中,它通常被实现为永久代或元空间。从Java 8开始替代了永久代,用于存储类的元数据,如类的静态结构。元空间不是JVM堆的一部分,而是使用本地内存,有助于避免内存溢出错误。

Java堆内存

        堆是用于存储对象实例和数组的内存区域,是垃圾回收器管理的主要区域,也是所有线程共享的。堆通常分为新生代和老年代,垃圾收集器定期清理无用对象以回收内存。

线程栈内存

         栈是每个线程独有的内存区域,用于存储局部变量、操作栈和方法调用信息。栈由栈帧组成,每个栈帧包含局部变量表、操作数栈、动态链接信息和方法返回地址。

本地方法栈

        本地方法栈用于支持JVM使用本地方法时的内存管理,类似于Java栈,但是用于管理本地方法调用。

程序计数器

        程序计数器是每个线程都有一个的内存区域,用于记录当前线程执行的字节码的行号指示器。线程切换时,程序计数器也会切换到下一个方法的起始点。

直接内存

        直接内存虽然不是JVM运行时数据区的一部分,但是Java NIO允许使用直接内存进行高效的I/O操作。直接内存不是由JVM管理,但是可以通过Java代码进行分配和释放。

        每个内存区域都有其特定的用途和GC行为,了解这些区域可以更好地理解Java程序的内存管理和性能调优,为后续我们谈论GC相关做好铺垫。

JVM内存模型实例

        老样子,上一章节我们从理论介绍来JVM内存区域划分及其各个区域应该存放的数据下面还是通过一段简单的代码来一起探究这个过程中数据是怎样流转的?

public class App {

    public static void main(String[] args) {
        SpringApplication sApp = new SpringApplication();
        // sApp.run(App.class, args);
    }

}

1、存放类的方法区&&元空间

其实在jdk1.8以后改成元空间更加利于我们的理解了,元空间存放元数据的空间,对于Java虚拟机谁是他的元数据呢?当然是class相关的数据呢,所以元空间(方法区当然是存放类相关数据的呢)。上述代码在JVM中的大概位置如图:

2、程序计数器

通过前面Java编译大家可以明白:我们编写好的源代码,会被编译成各种字节码指令,然后字节码指令会被一条一条的执行。所以JVM在加载class文件后需要有个可以执行字节码指令的工具,在JVM中这个工具就是字节码执行引擎。

但是字节码执行引擎只是用来执行指令的,具体执行到哪里了就需要另外程序计数器来记录。如下图所示:

Java虚拟机(JVM)是支持多线程的,它允许多个线程并发执行。在Java中,每个线程都有自己的程序计数器(Program Counter,PC),这个计数器是线程私有的。程序计数器用于存储当前线程正在执行的字节码指令的地址,确保线程在执行过程中能够正确地跟踪执行状态。

因此每一个线程执行字节码时,程序计数器会指向当前正在执行的指令。如果线程被暂停或阻塞,程序计数器会保持在当前指令的位置,这样当线程再次被调度执行时,可以从上次暂停的地方继续执行。

 如下图更加准确描述了他们之间的关系:

在Java中,代码的执行总是由线程来驱动的。即使是简单的main()方法,也是由JVM在启动时创建的名为main的线程来执行的。这个线程是Java程序的入口点,它负责执行main()方法中的代码。当main线程开始执行main()方法时,它的程序计数器会记录当前执行的字节码指令的地址。程序计数器是每个线程私有的内存区域,它的作用是确保线程能够跟踪其执行状态,包括当前执行到哪一行代码或哪一个字节码指令。

3、Java虚拟机栈 

上面介绍的程序计数器是用来记录指令执行的位置的且与每个线程有关,但是我们知道其实除了类变属性以外,其实每个方法都有自己的局部变量如下是的代码示例:

public class App {
    public static void main(String[] args) {
        SpringApplication sApp = new SpringApplication();
        //sApp.run(App.class,args);
        sApp.getRunListeners(args);
    }
}



public class SpringApplication {

    public String run(Class appClass, String[] args) {
        System.out.println("my Spring Application ");
        return "run args";
    }

    public String getRunListeners( String[] args) {
        System.out.println("My  getRunListeners ");
        String myRunListenersVar = "myRunListenersVar";
        this.getSpringFactoriesInstances(args);
        return "run args";
    }

    public String getSpringFactoriesInstances( String[] args) {
        System.out.println("My  getSpringFactoriesInstances ");
        String mySpringFactoriesInstancesVar = "mySpringFactoriesInstances";

        return "run args";
    }


}

上述代码SpringApplication类的getRunListeners方法与getSpringFactoriesInstances方法都有各自的局部变量,因此Java虚拟机也必须有一块内存空间去存该部分数据。

上述代码运行mian方法,会将首相会将App类里的main作为第一个栈帧压倒main线程所在的Java虚拟机栈,如下图所示:

进入SpringApplication#getRunListeners方法时,会将getRunListeners作为第二个栈帧压入main线程所在的Java虚拟机栈,同时在getRunListeners我们声明里局部变量myRunListenersVar变量,该变量在栈帧getRunListeners里。如下图所示:

方法继续向下执行,进入getSpringFactoriesInstances方法,会将getSpringFactoriesInstances压入main线程的Java虚拟机栈顶,如下图所示:

因为Java栈结构是先进后出,后续便会按照getSpringFactoriesInstances -> getRunListeners -> main 顺序进行弹栈,知道main方法运行结束。所以局部变量只会在方法内部生效,同时Java虚拟机栈又是线程内执行,所以后续介绍Java并发编程的时候我们说线程安全的时候也会提到,局部变量避免并发冲突等。

介绍完上述内容,我们再用一张图描述下:

4、Java堆内存

在介绍栈的过程中有意识的跳过了上述代码中关于创建SpringApplication这块的代码,我们再回头看看这段代码。

public class App {
    public static void main(String[] args) {
        SpringApplication sApp = new SpringApplication();
  
    }
}

上述 new SpringApplication()代码就是创建了一个SpringApplication对象实例,同样作为JVM也需要找个地方来存放对象实例数据,而这个地方被称作为Java堆内存。

当我们创建一个对象的时候,会将这个对象的实例数据放到堆内存中,然后把这个实例存放的引用返回给局部变量,这样我们就持有了对象实例的地址。

还是画一张图更加清晰一点:

5、整体流程

介绍整体流程之前,其实还有个区域就是Java为了区分我们写的方法和自己内置调用的方法,专门用来处理本地方法的调用区域管理,这块JVM称之为本地方法栈。至此整个流程就可以完整画出来了。

1、你的JVM进程会启动,就会先加载App类到内存里。然后有一个main线程,开始执行你的App中的main()方法。main线程是关联了一个程序计数器的,那么他执行到哪一行指令,就会记录在这里
2、main线程在执行main()方法的时候,会在main线程关联的Java虚拟机栈里,压入一个main()方法的栈帧。
3、接着会发现需要创建一个SpringApplication类的实例对象,此时会加载SpringApplication.class文件到内存里来
4、创建一个SpringApplication的对象实例分配在Java堆内存里,并且在main()方法的栈帧里的局部变量表引入一个sApp”变量,让他引用SpringApplication对象在Java堆内存中的地址。
5、main线程开始执行SpringApplication对象中的方法,会依次把自己执行到的方法对应的栈帧压入自己的Java虚拟机栈
6、执行完方法之后再把方法对应的栈帧从Java虚拟机栈里弹出来,

那么JVM中的各个核心内存区域的功能和对应的我们的Java代码之间的关系,就彻底理解

其实到这里JVM相关应该就结束了,但是在上面理论介绍的时候我们还提及到了直接内存,其实这块放到IO相关模块更加合适,上述提及到是为了给大家理解元空间做的实例。

同样最后的最后我们思考一两个问题,上述我们给JVM划分了各个内存区域放各种数据,随着程序的运行或者数据量变多了,内存放不下了怎么办呢?或者在分配内存的时候大家地址重复了又该咋整呢?

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

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

相关文章

浙江工商大学24计算机考研数据,好几个专业都接收调剂,计专复试线284分!

浙江工商大学(Zhejiang Gongshang University),简称“浙商大”(ZJSU),坐落于浙江省杭州市,是中华人民共和国教育部、中华人民共和国商务部和浙江省人民政府共建的浙江省重点建设高校&#xff0c…

代理的匿名级别有哪些?为什么匿名性很重要?

在互联网时代,代理服务器在许多领域都扮演着重要的角色。无论是个人用户还是企业,都可能需要使用代理来保护自己的隐私和数据安全。在选择代理服务时,匿名级别是一个重要的考虑因素。本文将介绍代理的匿名级别,并解释为什么匿名性…

Tampermonkey油猴 跨域请求下载图片示例

Tampermonkey油猴 跨域请求下载图片示例 前言项目目标网站代码编写 运行效果 前言 需要用油猴采集并下载一个网站的图片,直接下下不了,搜了一下,是禁止跨域,使用CORS Unblock也不行,所以使用油猴自带的GM_xmlhttpRequ…

35 - 最后一个能进入巴士的人(高频 SQL 50 题基础版)

35 - 最后一个能进入巴士的人 -- sum(weight) over(order by turn) as total,根据turn升序&#xff0c;再求前面数的和 selectperson_name from(selectperson_name,sum(weight) over(order by turn) as totalfromQueue) new_Queue wheretotal<1000 order by total desc lim…

四川汇聚荣科技有限公司靠谱吗?

在如今这个信息爆炸的时代&#xff0c;了解一家公司是否靠谱对于消费者和合作伙伴来说至关重要。四川汇聚荣科技有限公司作为一家位于中国西部地区的企业&#xff0c;自然也受到了人们的关注。那么&#xff0c;这家公司究竟如何呢?接下来&#xff0c;我们将从多个角度进行深入…

高考填报志愿(选专业),怎样找准自己的兴趣?

在很多的高考报考指南中&#xff0c;第一要点&#xff0c;都会建议我们根据自己的兴趣来选择自己的专业。很多人虽然是依据这条规则&#xff0c;选择了自己大学的专业。却依然在学习的过程中发现&#xff0c;好像自己对这个专业并不是那么的有兴趣。 甚至对专业学习深入了解之…

2-13 基于matlab的电力负荷预测

基于matlab的电力负荷预测&#xff0c;论文阐述了负荷预测的应用研究现状&#xff0c;概括了负荷预测的特点及其影响因素&#xff0c;归纳了短期负荷预测的常用方法&#xff0c;并分析了各种方法的优劣&#xff1b;采用最小二乘支持向量机&#xff08;LSSVM&#xff09;模型&am…

web中间件漏洞-Redis漏洞未授权访问漏洞-写webshell、写ssh公钥

web中间件漏洞-Redis漏洞未授权访问漏洞 利用redis未授权访问漏洞写webshell 利用redis未授权访问、攻击机向服务器写入webshell 从服务器查看写入的webshell 菜刀连接 利用redis未授权访问漏洞写ssh公钥 kali生成rsa公私钥对 ssh-keygen -t rsa 将公钥id_rsa.pub写入文…

pytets测试框架中如果需要运行多个测试套件时pytest.ini文件设置

pytets测试框架中如果需要运行多个测试套件时pytest.ini文件设置方法 testpaths testcases/fenmi testcases/weixin testcases/Zgen

【物联网】室内定位技术及定位方式简介

目录 一、概述 二、常用的室内定位技术 2.1 WIFI技术 2.2 UWB超宽带 2.3 蓝牙BLE 2.4 ZigBee技术 2.5 RFID技术 三、常用的室内定位方式 3.1 信号到达时间 3.2 信号到达时间差 3.3 信号到达角 3.4 接收信号强度 一、概述 GPS是目前应用最广泛的定位技术&#xff0…

DVWA 靶场 CSP Bypass 通关解析

前言 DVWA代表Damn Vulnerable Web Application&#xff0c;是一个用于学习和练习Web应用程序漏洞的开源漏洞应用程序。它被设计成一个易于安装和配置的漏洞应用程序&#xff0c;旨在帮助安全专业人员和爱好者了解和熟悉不同类型的Web应用程序漏洞。 DVWA提供了一系列的漏洞场…

【Excel经验】字符串处理方法

概览-公式汇总 序号公式功能公式公式示例公式说明1把多列内容拼接在一起&#xff0c;作为新的一列的内容CONCATENATE (text1,text2,…)CONCATENATE(A2,“#”,B2,“”,C2)用于根据多个列的内容拼成我们指定格式的内容&#xff0c;拼接的内容通常来源于原始数据&#xff0c;同时…

若电路板上的二极管损坏后怎么确定型号呢?

若电路板上的二极管损坏后&#xff0c;还可以看清原来管子的型号&#xff0c;换用一个同型号的二极管即可。若看不清型号或管子未标注型号&#xff0c;一般可以根据该二极管在电路中的作用来代换。电路板上的二极管坏了&#xff0c;如何确定它的型号&#xff1f;。 一般来说看…

【vue3|第12期】Vue3的Props详解:组件通信

日期&#xff1a;2024年6月19日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

SpringBoot开发实用篇(一)

一&#xff1a;热部署 1&#xff1a;手工启动热部署 关于热部署 重启&#xff08;Restart&#xff09;:自定义开发代码&#xff0c;包含类、页面、配置文件等&#xff0c;加载位置restart类加载器重载&#xff08;Reload&#xff09;:jar包&#xff0c;加载位置base类加载器…

阿里云发送验证码流程

目录 1. 阿里云短信服务简介 2. 阿里云验证码发送流程 2.1 申请阿里云短信服务 2.2 短信模板及阿里云秘钥 1.开发者可以在自己的应用程序中集成短信发送功能。绑定发起测试的手机号&#xff0c;需要绑定的手机号才能成功发送验证码&#xff0c;其他的用户手机号发送的验…

统信UOS 安装二级制版MySQL8.4

统信UOS 安装二级制版MySQL8.4 建立MySQL用户和用户组 sudo groupadd mysqlsudo useradd -r -g mysql -s /bin/false mysql下载MySQL安装包 wget https://cdn.mysql.com//Downloads/MySQL-8.4/mysql-8.4.0-linux-glibc2.28-x86_64.tar.xz解压缩MySQL安装包 sudo tar -xvf m…

nginx架构基本数据结构配置模块请求详解

初探nginx架构 众所周知&#xff0c;nginx性能高&#xff0c;而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢&#xff1f;这一节我们先来初识一下nginx框架吧。 nginx在启动后&#xff0c;在unix系统中会以daemon的方式在后台运行&#xff0c;后台进程包含一…

鸿蒙 HarmonyOS NEXT星河版APP应用开发—上篇

一、鸿蒙开发环境搭建 DevEco Studio安装 下载 访问官网&#xff1a;https://developer.huawei.com/consumer/cn/deveco-studio/选择操作系统版本后并注册登录华为账号既可下载安装包 安装 建议&#xff1a;软件和依赖安装目录不要使用中文字符软件安装包下载完成后&#xff0…

mac电脑守护神CleanMyMac2024免费版本下载

&#x1f31f; 电脑的守护神&#xff1a;CleanMyMac&#x1f47e; 亲爱的数码控们&#xff0c;是不是每次看到电脑上满满的垃圾文件和缓慢的运行速度就感到头疼呢&#xff1f;别怕&#xff0c;今天我要来给你们安利一款神奇的小帮手——CleanMyMac&#xff01;它可是我们电脑的…