探索JAVA神秘运行机制:揭秘JVM内存区域

目录

1. 前文回顾

2.内存区域的划分

2.1 存放类的方法区

2.2  程序计数器

2.3 Java虚拟机栈

2.4 Java堆内存

2.5  其他内存区域

3. 核心内存区域运行流程

4. 总结

1. 前文回顾

        上一篇我们一起探索了Java的整体运行流程,类加载器以及类的加载机制,了解了从编译打包后生成的字节码文件,JVM启动后,类的加载时机,加载之后验证,准备,解析都是做什么的,以及尤为重要的是准备阶段和初始化阶段,是如何为类分配内存空间的?然后类加载器的规则是什么?来看下下图,简单回顾下内容

2.内存区域的划分

        接上一篇的问题,我们编写的类在内存中到底是什么样子的,又是如何进行划分的呢?在看之前想一个问题,我们都知道,就是我们要用的类通过类加载器加载后,在内存中会分配一块空间出来进行存储,我们看一个类,主要分为类名称、属性、方法、代码块这几个部分,那么他们在内存中是如何存储的,是统一的放到一起,还是分开来放的?我们执行的代码,调用的方法是不是要一个个的执行他们在内存中是如何进行的,方法中的变量是不是要放到一起?我们带着这些问题,一起来看下内存区域的划分。

2.1 存放类的方法区

        这个方法区是在JDK1.8以前的版本里,代表JVM中的一块区域。主要是放从".class"文件里加载进来的类,还会有一些类似常量池的东西放在这个区域里。但是在JDK1.8以后,这块区域的名字改了,叫做"Metaspace",可以认为是"元数据空间”这样的意思。当然这里主要还是存放我们自己写的各种类相关的信息(主要是包括类信息、常量、静态变量等类的结构信息)。其实,我倒是认为jdk1.8 升级后,改的名字更加的贴切,元数据信息空间,也就是主要存储类的元数据信息。

2.2  程序计数器

        程序计数器这个的概念理解,其实说的简单点就是:我们写好的Java代码会被翻译成字节码,对应各种字节码指令。所以当JVM加载类信息到内存之后,实际就会使用自己的字节码执行引擎,去执行我们写的代码编译出来的代码指令,而在执行的过程中,由于是多个线程执行的,为了保证每个线程执行的不错误,能够方便的知道执行到那个字节码位置,需要有一个东西来记录下他们执行的位置,这个就引出来“程序计数器” 这一个概念了。那么我们现在明确了"程序计数器”这个概念:用来记录当前执行的字节码指令的位置的,也就是记录目前执行到了哪一条字节码指令。

2.3 Java虚拟机栈

        这个Java虚拟机栈概念也很好理解,我先一步一步的引入这个概念,首先我们都知道Java代码在执行的时候,一定是线程来执行某个方法中的代码,就是最主要的main线程执行main()方法的代码指令的时候,也会通过main线程对应的程序计数器记录自己执行的指令位置。但是呢,在执行方法内部是时候,我们通常会定义一些局部变量出来,此时问题来,我们用的这些局部变量,每个线程执行这个方法的时候都会使用这个局部变量,是不是要有个地方用来储存吧,因此,JVM必须有一块区域是来保存每个方法内的局部变量等数据的,这个区域就是Java虚拟机栈。

每个线程都有自己的Java虚拟机栈,比如这里的main线程就会有自己的一个Java虚拟机栈,用来存放自己执行的那些方法的局部变量。如果线程执行了一个方法,就会对这个方法调用创建对应的一个栈帧,栈帧里面包含的有方法的局部变量表、操作数栈、动态链接、方法出口等东西,这里大家先不用全都理解,我们先关注局部变量。

        比如main线程执行了main()方法,那么就会给这个main()方法创建一个栈帧,压入main线程的Java虚拟机栈,同时在main()方法的栈帧里,会存放对应的"replicaManager"局部变量,我们称之为把局部变量压入栈帧, 等到方法执行完毕后,局部变量就会从这个Java虚拟机栈里面出栈。这个就是我们平常使用方法内部的局部变量的执行过程。

        简单的理解这个是我们写的类里面执行的方法,中间使用到的局部变量这些东西,有个客栈或者理解成工具箱,专门储存这些东西,等到方法执行的时候,会把局部变量进来,等待使用,使用完了就移除来了,这个过程就是局部变量的入栈出栈。

2.4 Java堆内存

        我们前面说了,Java的类结构等信息存在了方法区,线程执行的字节码执行的位置信息在程序计数器中,类的方法内局部变量信息在运行时,存储在Java虚拟机栈中,那么还剩下什么呢?我们类写好了,也都已经加载完了,但是我们还有个操作是什么呢?对象的实例化,对象实例化我们放在那呢?JVM也为我们想到了,这块区域就是堆内存。Java堆内存,这里就是存放我们在代码中创建的各种对象的

public class Kafka {public static void main(String[] args){ReplicaManager replicaManager = new ReplicaManager();replicamanager.loadReplicasFromDisk();}
}

        我们在代码中用的时候呢,其实是结合着来的,Java堆内存是存放实例化的对象,例如,我们写的代码执行的main() 方法,里面的局部变量被放入到了Java虚拟机栈中,然后又进行了实例化对象,Java堆内存区域里会放入类似ReplicaManager的对象,然后我们因为在main方法里创建了ReplicaManager对象的,那么在线程执行main方法代码的时候,就会在main方法对应的栈顿的局部变量表里,让一个引用类型的"replicaManager"局部变量来存放ReplicaManager对象的地址。 相当于你可以认为局部变量表里的"eplicaManager"指向了Java堆内存里的ReplicaManager对象。

2.5  其他内存区域

        上面说了平常我们主要用到的一些区域,我们其实还有其他的一些区域,比如IO相关的,NIO相关的,网络Socket相关的,如果大家去看他内部的源码,会发现很多地方都不是Java代码了,而是走的native方法去调用本地操作系统里面的一些方法,可能调用的都是c语言写的方法,或者一些底层类库,比如下面这样的:public native int hashCode(); 在调用这种native方法的时候,就会有线程对应的本地方法栈,这个里面也是跟Java虚拟机栈类似的,也是存放各种native方法的局部变量表之类的信息。

还有一个区域,是不属于JVM的,通过NIO中的alocateDirect这种AP,可以在Java堆外分配内存空间。然后,通过Java虚拟机里的DirectByteBuffer来引用和操作堆外内存空间。其实很多技术都会用这种方式,因为有一些场景下,堆外内存分配可以提升性能。

3. 核心内存区域运行流程

        jvm内存区域的划分,我们已经讲完了,那么我串起来整体过下他的流程,这样就更能加深印象,先来一个图:

根据上图我们再来一段代码,整体的说下流程:

public class Kafka {public static void main(String[] args){ReplicaManager replicaManager = new ReplicaManager();replicamanager.loadReplicasFromDisk();}public class ReplicaManager{private long replicaCount;public void loadReplicasFromDisk(){Boolean hasFinishedLoad = false;if(isLocalDatacorrupt()) {}}public Boolean isLocalDatacorrupt(){Boolean isCorrupt = false;return isCorrupt;}}
}

        我们一起来看下上面的过程,首先,你的JVM进程会启动,就会先加载你的Kaika类到内存里。然后有一个main线程,开始执行你的Kaika中的main()方法。main线程是关联了一个程序计数器的,那么他执行到哪一行指令,就会记录在这里。其次,就是main线程在执行main()方法的时候,会在main线程关联的Java虚拟机栈里,压入一个main()方法的栈帧。接着会发现需要创建一个ReplicaManager类的实例对象,此时会加载ReplicaManager类到内存里来。然后会创建一个ReplicaManager的对象实例分配在Java堆内存里,并且在main()方法的栈帧里的局部变量表引入一个“replicaManager”变量,让他引用ReplicaManager对象在Java堆内存中的地址。接着,main线程开始执行ReplicaManager对象中的方法,会依次把自己执行到的方法对应的栈顿压入自己的Java虚拟机栈,执行完方法之后再把方法对应的栈顿从Java虚拟机栈里出栈。

        其实大家理解了这个过程,那么JVM中的各个核心内存区域的功能和对应的我们的Java代码之间的关系,就彻底理解了。

4. 总结

        好了,最后我们做个总结,JVM为我们把各个地方的区域都做好了设计,我们最后来梳理下:(1)方法区:Java类的结构信息,元数据存储区域;

       (2)程序计数器:用来记录当前执行的字节码指令的位置的;

       (3)Java虚拟机栈:用来保存每个方法内的局部变量等数据的;

       (4)Java堆内存:用来存放我们在代码中创建的各种对象的;

       (5)其他的内存区域:本地方法栈、堆外内存;

经过内存区域的划分了解,我们知道了JVM是如何对内存进行划分的,了解了Java的类中各个部件在内存中是如何存储的?我们解决了存储的问题。那么,他在运行过程中又是如何进行调用这些数据的,调用过程中又是如何进行回收的呢?会不会出现内存溢出,又是如何处理的呢?我们带着这些疑问,等到下一篇文章在说,JVM的垃圾回收机制来解答。

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

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

相关文章

去了字节跳动,才知道年薪 30w 的测试工程师有这么多?

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

solidjs 中方便的修改对象与数组的值

createSignal 众所周知, React 想方便的修改 useState 中的对象或数组, 需要使用第三方库 Immer , immer 官方直接支持 React, 类型与智能提示都很不错, solidjs 中有一个第三方的包.封装了 createSignal 与 Immer , 提供了更好的 ts 类型 与 智能提示 https://github.com/…

logstack 日志技术栈-03-日志最佳实践

收集日志 日志管理的第一件事,就是日志的收集。日志收集是开发者必备的技巧,不管是哪个开发语言,哪个开发平台,日志收集的插件都是有很多选择的。 例如:.net 平台大家钟爱的log4net,支持多种存储方式(文件…

会体言一心文-码代-4202

简明版本 最近感悟就是在“常规赛”中,大部分奇技淫巧远不如官方教程。 我使用大模型工具快一年的时间所积累的经验远不如认真看看官方教程。 官方教程 里面有一点就可以秒99%的工具人,“文心一言7*24小时在线,伴你左右。 ” 结合文心一言…

基于STM32单片机设计的智能水温控制系统

一、前言 1.1 项目介绍 【1】项目功能介绍 随着科技的快速发展和智能化生活的普及,人们对生活品质的需求日益提高,对家用电器自动化与智能化控制的要求也越来越高。在家庭用水场景中,热水器、浴缸以及智能水暖系统的温控需求尤为突出。传统水温控制系统往往功能单一、操作…

中仕教育:考上选调生之后能不去吗?选调生和公务员哪个比较好?

选调生,是指经过选拔、培训、考核等一系列程序,选拔出的人才。选调生通常需要在基层锻炼一段时间,然后根据工作表现和能力得到提拔。 考上选调生之后能否不去,有以下两种情况。 1.如果通过选调笔试,但是并未参加后续…

组件开发遇到的问题(vue的问题)

组件的开发和引用 <template><div class"xx">组件</div> </template> <script>export default {name: viewMore,components: {},data() {return {}}} </script> <style scoped>可以定义组件都有的样式 </style> …

2788.按分隔符拆分字符串

前言 力扣还挺上道&#xff08;bushi&#xff09;&#xff0c;今天第一次写每日一题&#xff0c;给了个简单等级的数组题&#xff0c;我只能说&#xff0c;首战告捷&#xff08;小白的呐喊&#xff09;&#xff0c;看看这每日一题我能坚持一天写出来&#xff0c; ok&#xff…

Javaweb之SpringBootWeb案例员工管理之新增员工的详细解析

SpringBootWeb案例 前面我们已经实现了员工信息的条件分页查询以及删除操作。 关于员工管理的功能&#xff0c;还有两个需要实现&#xff1a; 新增员工 修改员工 首先我们先完成"新增员工"的功能开发&#xff0c;再完成"修改员工"的功能开发。而在&q…

在前端开发中需要考虑的常见web安全问题和攻击原理以及防范措施

文章目录 一、XSS攻击1、反射型XSS攻击原理2、DOM型XSS攻击原理3、存储型XSS攻击原理 防范措施 二、CSRF攻击攻击原理&#xff1a;防范措施&#xff1a; 三、点击劫持攻击原理&#xff1a;防范措施&#xff1a; 四、项目中如何预防安全问题 随着互联网的发展&#xff0c;Web应用…

2024QS世界大学排名完整榜单

第1位: 麻省理工学院 第2位: 剑桥大学 第3位: 牛津大学 第4位: 哈佛大学 第5位: 斯坦福大学 第6位: 帝国理工学院 第7位: 苏黎世联邦理工大学&#xff08;瑞士联邦理工学院&#xff09; 第8位: 新加坡国立大学 第9位: 伦敦大学学院 第10位: 加州大学伯克利分校 第11位…

Self-RAG:通过自我反思学习检索、生成和批判

论文地址&#xff1a;https://arxiv.org/abs/2310.11511 项目主页&#xff1a;https://selfrag.github.io/ Self-RAG学习检索、生成和批评&#xff0c;以提高 LM 的输出质量和真实性&#xff0c;在六项任务上优于 ChatGPT 和检索增强的 LLama2 Chat。 问题&#xff1a;万能L…

10分钟完成权限系统全流程开发

背景 首先问下chatgpt,权限系统的模型有哪些&#xff1f; 基于上述的结论&#xff0c;我们选择基于角色的访问控制(RBAC)&#xff0c;请从数据库设计、接口文档、代码实现、单元测试四个方面分别详细描述每个部份需要实现的内容。 数据库实现 针对上述的数据库设计部份&#…

格局打开!前端未死,只是要求变高了

本文笔者会从以下几个方面分享&#xff0c;希望能够帮助正在迷茫的前端小伙伴提供一点思路&#xff01; 逛技术博客 不局限框架 全栈工程师兴起 关注前沿 写技术文章 录制前端视频 总结 2024年了&#xff0c;没工作的找到工作了吗&#xff1f;有工作的加薪了吗&#xff1f;加薪…

【高等数学之极限】

一、引言 我们先思考一下&#xff0c;上面三个表达式&#xff0c;是否可以将极限值直接代入求值&#xff0c;我们在计算之前需要先分析一下&#xff0c;如果将极限值代入&#xff0c;那么表达式将会变成什么形式? 经过上面的分析&#xff0c;我们发现第一个式子可以直接带入&a…

浪花 - 主页开发

一、简易版主页 1. 主页展示用户列表 <template><!--推荐用户列表--><van-cardv-for"user in userList":desc"user.profile":title"${user.username}(${user.planetCode})":thumb"user.avatarUrl"><template #…

VUE表单中多个el-upload上传组件共享回调函数解决方案

产品需求界面&#xff1a; 在产品配置页面表单中需要上传多个图片&#xff0c;项目中上传组件采用Element Plus 中的 el-upload&#xff0c;目前问题是每个上传组件都需要实现自己的回调&#xff0c;比如:on-change&#xff0c;采用官方推荐标准代码如下&#xff1a; <el-fo…

java中的时间API

Created: January 19, 2024 2:31 PM 1、旧版时间API的缺点 在java1.0中使用java.utol.Date类表示时间&#xff0c;该类存在很多问题&#xff0c;例如时间零点是1900年1月0日&#xff0c;例如想到表示2024年1月19日就需要如下定义&#xff0c;此外Date也无法表示时间、包含默认…

西瓜书读书笔记整理(十二) —— 第十二章 计算学习理论

第十二章 计算学习理论&#xff08;上&#xff09; 12.1 基础知识12.1.1 什么是计算学习理论&#xff08;computational learning theory&#xff09;12.1.2 什么是独立同分布&#xff08;independent and identically distributed, 简称 i . i . d . i.i.d. i.i.d.&#xff0…

Mysql运维篇(一) 日志类型

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人&#xff0c;如有侵权请留言&#xff0c;我及时删除。 一、mysql相关日志 首先&#xff0c;我们能接触到的&#xff0c;一般我们排查慢查询时&#xff0c;会去看慢查询…