粉丝71获赞272

大厂 j 文本并发编程面试题解析四 j 文文有哪些内存区 基于版本中间呢?它其实最重要的一块内存,我们把它称之为运行时数据区,那么运行时数据区呢,它主要是按照两种来划分的啊,划分成两大块, 比如说有县城共享的区域,有县城私有的区,那么在县城的私有区域里面呢,包含的虚拟基站啊,虚拟基站呢,他是扎瓦运行扎瓦方法啊,以及 gym 在运行扎瓦方法中间去存储 他这个方法所需的一些数据啊,指令啊,还有返回地址。他本质上面这个虚拟基站啊,他是一个站的结构,所以呢,他也是一个先进后出,他主要是存储扎瓦方法运行的一些相关的数据,指令等等之类的。那么除了扎瓦方法,我们也知道在扎瓦中间,我们还 运行本地方法,也就是内体方法啊,所以呢,在虚拟机当中同样还有一个本地方法站啊,本地方法站他的实现呢,其实跟虚拟机站非常的类似啊,但是他呢服务的对象,他是内体方法,是本地方法,也就是用那种 c 语言或者 c 加加语言写的。 除此之外的话呢,在县城私有的区域,也就是说你每一启动一个县城,他都有一个程序计数器,那么这个程序计数器呢,是用来干嘛呢?他是用来去记录我们每一个县城当前正在执行的这个字解码的一个地址 啊,你也可以称之为这个自检码的一个行号。比方说我们运行这个慢方法,运行在第十三行之后,对不对?可能县城被调度出去了,那这个时候我们程序计数器,他就会记录当前这个县城正在执行的自检码的地址是十三号, 如果这个县城啊,后面呢又被唤醒了,又被调度执行了,那么我们的代码,我们的这个职员们又会从刚才程序计数器记录的那个地址或者是自检码的这个行号开始接着执行。所以呢,程序计数器啊,往往在 基元门中间或者是多线城城当中啊,他是有相当意义的,可以确保我们多县城或者是 cpu 调度的一个执行 好。那么虚拟基站,本地方法站,还有程序技术期,他就构成了现成私有的一个部分,也就是说每一个县城他都有单独的一份,那除了这个之外,还有一块区域,他是现成共享的,比如说像方法区, 方法去了,其实大家很多名称啊,在 gdk 一点七之前,你可以叫他永久贷,在 gdk 一点八之后啊,我们可以 叫他圆空间,那么这个是有啥区别呢?其实方法区他的定义是在虚拟机规范当中,也就是说无论你是哪一款虚拟机, 哪怕是偶尔克公司的好的 spat, 还是 ibm 的虚拟机,还是说你自己研发的虚拟机,对不对?你按照虚拟机规范来去定义的话,你必须要去实现方法去 啊,你叫永久贷也好,你叫圆空间也好,这都是不同 gdk 的版本,或者是不同 gdk 的厂商,他针对方法去的一个实现, 所以的话呢,我在基本内存中间,我用方法去进行统称,具体的名称的话,要依赖他的一个 gvm 的实现,那么这个方法区里面他会存放什么呢?他主要存放的是一些静态的资源,比如说像内的信息,比如说像长量池,还有像 像一些方法的数据,还有一些方法的代码,所以呢,方法区里面他存放的都是一些静态的,并且可以被所有县城给共享的一些东西,所以呢,他同样属于县城共享的区域。那么县城共享的区域除了方法区之外,还有一块最重要的就是堆, 因为堆是基于文中间,基于文中间最大的一块内存啊,我们几乎深几乎所有对象他都在对中间进行分配,所以啊,堆往往是我们关注的一个重点啊。当然呢,堆的划分他有, 嗯,他不是我们看起来的一个整体啊,他里面有一个详细的划分,在后续的面试题中间我会进行一个详细的讲解。那么我们总结一下啊,如果说面试官问你,职业员们有哪些内存区域啊?你要给他说清楚啊,这个虚拟鸡蛋、本地方法、 挑战程序、计数器这三个部分呢,属于现成私有的,他跟方法的运行息息相关。那么除此之外的话,方法区他主要跟内跟静态变量、敞亮这些静态的东西相关,并且他是县城共享的,被所有的县城共享。 那么最重要的一块其实还是堆,因为几乎所有的对象他都在堆中间进行分配,所以呢,你还要讲一下,堆其实是对象分配的一个 区域,与此同时他还跟 gvm 中间的垃圾回收息息相关。那么这个呢,就是我们讲的 gvm 中间有哪些内存区域。

运行时数据区,首先我们来看一下概念啊,什么是运行时数据区?运行时数据区的话,所谓运行时数据区就是在 运行过程中当中 g m 在运行过程当中,我们会把这个所管理的这一块,刚才这个运行是内存这一块呢,我们把它给划分成不同的若干个数据区域, 也就是说他里面的所有对象的创建的话,他可能是放在 a 区域,也有可能放在是 b 区,也有可能是放在 c 区域,对不对?所以的话他也是有一个区域的划分,他不是说随便放的, 那我们就是主要分为两个部分, j r。 在 g m 在运营过程当中的话, 他主要是把内存分为我们的两大两大部分,一部分就是现成。室友稍等一下啊, 怎么了?磕着了?那怎么哭了呢? 他怎么弄啊? 腿疼是不是 找着了? 不吃药是不是? 哎,不好意思啊,刚才家里小孩,然后腿疼过去看了一下,哎,不好意思,我现在回过来了, 好,喝口水。我们接着我们刚才的内容啊,运行时数据区这一块的话 啊,就是把他所管理的这块内存,我们刚才说的这个管理这块内存,我们把它划分为若干个不同的数据区啊,这块区域的话, 我们所创建的这些所有的对象,有可能话就是放在 a 区,也有可能放在 b 区,也有可能是放在 c 区, 那 g m 是怎是把是它里面这块内存区域吧?是真实的景象,是怎么划分的呢?其实它是由两部分内容来构成的,一部分就是这个线程私有, 一部分就是这个,另外一部分就是这个啊,现成共享,现成共享, 县城共享。首先这个县城共享这块的话,他也他又做了一些划分。我们你比方说我们的一个应用程序启动,对不对?你比方我现在在给大家讲课,又有一个我启动了两,呃,有,假如说我启动了两个软件,一个是这个 ppt, 一个这个,一个是这个直播伴侣,就是给大家直播的一个平台,一个是我通过直播平台呢,可以给大家直播,也可以给大家做一些互动信息等等等等,那好吗?那就相当于是假如我们这个直播伴侣是一个县城,县城一, 然后呢这个 ppt 呢?是线程二,就相当于我这个电脑的话就起了两个线程,以两个私有的线, 县城就是县城一和县城二,我们的每一个县城呢又包含了相关的一些信息,我们里面包含了这个程序计数器,包含了这个本地方法站,包含了这个虚拟机站。 县城私有区域呢?是跟随县城,意思是什么呢?县城是这个私有县城呢,是跟着应用程序启动而启动,也就是说 你的应用程序启动完了以后,如果你的应用程序消亡了,那这个县城的话也会跟随你的县城,嗯,执行完了以后呢,会释放掉,那同样他也会跟着释放掉,对不对?也就是县城私有这一块区域的应用呢?就是说我用完了, 我释放掉了,那就他也就不存在了。所以说在县城私有区域这块的话,他可能有县城一、县城二、县城三、县城四、县城五,他会有有可能会有更多的县城,然后在这块区域里面存在, 而且是每一个县城的创建的话,它都会包含这个程序计数器、本地方法站和虚拟基站这三部分类型信息。 另外的话县城共享这一块的话,它包含了主要是有两大部分,一部分呢是我们的堆,一部分呢是我们的方法区。县城共享这一块区域的话,是只要我们的 gm 运行起来以后呢,这块区域他就会被初始 话,他就会被出,是吧?他就会被创建,他就会被创建,这样的话就是说 就可以给我们所有的私有现成,也就是说假如说是现成一和现成二,我们就可以给他们直接进行教用 调用我们这些共享县城里面的一些数据啊,比方说我们的一些对对象,是吧?创建的你比方 a 啊,这个长量,哎,这个长量,这个长量的话哈,长量的话是直接放在我们的方法区内,然后启动完了以后, gum 启动用完以后,这个数据已经在我们的方法区里面存在了,那我们线层一在调用的时候,就直接从我们的内存里 你们去拿,那这样的话他的速度是不是会很快,对不对?他不会说哦,你还得再去初始花呀,我每创建一次都要去初始花呀,那这样的话一是耗内存,二是耗 cpu, 对不对? 所以的话我们就会什么呢?那这两块信息的话就很明朗了, 他主要是,呃,就是有线层私有和线层共享这两块区域来组成的。那现在的话我们就可以大家这可以思考一个问题, 那就是说现成私有这块区域比较重要呢?还是现成共享这块区域比较重要呢?我们应该先分析哪一部分?大家觉得我们需要先分析这个现成私有的这一部分的话 可以在我们的这个平台上面互动信息这块我们可以刷一,然后需要分享共享县城这块的,大家可以觉得这部分比较重要的,大家可以刷一个二啊。 呃,我个人感觉啊,因为 g m 在启动的时候呢,他会先把我们县城共享这块区域的话进行初始化,然后并进行创建。 那我们就先把这个县城共享这块区域化,简单的跟大家先来沟通一下,先来说一下。

你是不是还没有完全搞懂 jbm 的内存模型?欢迎来到新一期的小欧说编程,今天来给大家分享一下 jbm 的内存模型。在日常的面试中, jbm 的内存模型是我们绕不开的一个话题。 jbm 的内存模型一共分为五大块, 分别是虚拟机上程序计数器,本地方法站、堆还有方法区。这个方法区有两种实现,在 jdk 七之前, 它的实线是叫永久带,在 jdk 一点八之后,它的实线则换成了圆空间。我们先来解释一下虚拟基站,虚拟基站存储的是方法的一些局部变量,程序计数器存储的则是我们的程序执行到了哪一步。本地方法站和虚拟基站是类似的, 只是这里面存储的是一些本地方法的信息,存储的是一些西家家编写的本地方法的一些信息,而这里的堆存储的就是我们扭出来的一些对象的一些相关信息。 方法区存储的则是一些静态变量,还有一些层量,还有一些静态方法,以及我们的一些类信息。我们的 class 文件在进行被类加载之后,会产生一些类的信息,就是存储在咱们的这个方法区里面。眼睛比较尖的同学可以发现,这个图里面把这五个区分别标了两种颜色,红色代表的是现成私有的, 每个县城都会开辟单独的一块内存,而我们蓝色是县城共享的,也就是所有的县城都能访问到这个堆里面的信息,还有这个方法区里面的一些相关信息。下面我们用一串简单的代码来详细的给大家讲一下 这些存储的过程,我们这里面可以看到这一串代码,这串代码很简单,就是这里面有两个变量,我们来我们来通过这两个变量去调用这个创建的方法来创建出一个人类的类实力,然后再将其打印,下面我们来看一下它的解析过程。 我们在执行卖方法的时候,这个 id 是这个卖方法的一个局部变量,此时代码执行到这一行的时候,我们就会将 id 加载到虚拟基站里面。在执行到第二行的时候,因为我们的实菌类型它不是一种基础类型,这里面就会进行类的创建,我们会先创建一个实菌的类,创建在咱们的堆内存里面, 然后这个是类的地址,这不算,在创建的时候,他是会存储在我们的这不算常见词里面,然后这个是他的类地址, 这个是吃不穿的信息,然后这里面我们就会加载这个内幕的变量,然后这个变量的值就是我们的类地址,下面我们就去调用了这个创建方法,我们再去调用那个创建方法的时候,这里面的 id 和我们的 mate 发里面的 id 不是同一个,所以它这里面也会 往这个站里面塞入一个 id, 再到下一步,这里面的这个内幕和之前的那个内幕也是不一样的,所以我们这里面也会在站里面 塞入一个内幕的变量,但是他们的指向的类地址都是同一个,都是咱们这个常见词里面的这个对象代码在执行到这一行的时候就会去扭对象,扭对象的时候他就会在堆里面去,他就会在堆里面去开辟一块空间,用来存储这个类的信息,此时我们的账里面也会填充这个变量的信息, 这变量的值指向的就是这个类地址,这里面他通过类地址找到了堆里面的空间,然后再进行给他复制,分别复上 id 还有内幕, 最后返回这个变量。当我们的代码在执行完这个方法的时候,属于这个方法的变量就会依次从这个站里面进行弹出, 随后代码执行到这一行,我们的内方法也获得了一个人的变量,此时这个变量也会进账。 最后我们在结束内分法的执行之后,这些属于内分法的变量也会进行出证, 这个就是代码的一些完整的过程。这里面我们可以看到我们的账里面存储的一些变量信息,在执行完方法之后就会依次出账,但我们堆里面存储的一些对象信息则不会被销毁,那他们什么时候会被回收呢? 当我们在堆里面存储的这些对象信息没有指针指向的时候,在下一次垃圾回收之后就会进行回收,就会将我们堆里面的这些对象信息进行销毁。最后再用代码来给大家看一下我们的方法区域里面存储的到底是哪些信息。我们可以进入我们的代码里面,我们可以通过反变异这个代码就可以看到 一个 class 文件在进行类的加载的时候,会产生一些类的信息,这些信息就是存储在我们的方法区里面, 现在我们执行一下反变异这里面我们通过执行这个反变异的命令,我们可以看到 一个 class 文件在被类解析之后会产生这些类的信息,我们的方法区里面除了存储一些类的信息之外,还会存储一些产量,还有一些静态方法的一些信息,这个就是本期的分享视频,我们下期再见, nice。

我们从这一章节呢开始讲解 java 内存模型程序计数器, 在讲程序计数器之前呢,我们先大致的介绍一下加 j v m 的一个内存的一个组成,这呢有一个整体的概览,方便于我们学,方便于我们学下面的一个知识。 我们首先呢有一个原文件,这个原文件呢就是我们所说的开发的就是 加码文件,这原文件呢它不能直接运行,它需要编译成一个 class 文件,这个 class 文件呢就是我们所说的字解码文件了,这些字解码文件仍然不可以直接运行, 他呢是需要通过内加,在我们用的时候啊,他需要通过内加载下把它加载到 jvm 内存区域, gvm 内存区域呢,我们之后呢被调动的时候啊,他才能通过借助这种 gbm 的一个运行区啊来进行正常的执行。那么呢我们介绍一下,就是我们的 gbm 有五大区域的大致的每个区啊,他是一个做什么用处的? 首先介绍这种原数据空间,他呢我们加载一个克拉斯的时候啊,这个类模类信息啊,包括我们的字段方法 等属性的一个描述,这封信息啊都会存放在我们张杰这个元素元元空间里面,这个元空间呢在接地 k 一点八亿钱,这一钱它叫呢方法区, 这个方画区呢,它跟我们当前语言空间的功能也差不多,只是在 gdk 的一点八的时候啊, 以后啊,他就把这个原空间直接玻璃的 g v m 内存区啊,只把它直接存到直接内存里面,到时候讲内存原数据空间的时候,我们再详细介绍这一部分的知识, 本地方法在呢可能是一个专门用于调度调用第三方语言的一个一个类似于桥梁一样,这个桥梁呢,比如类似于 window 的 d d r 文件, d r 文直线的时候结 v m 加把 v 料兼容, 能够调动第三方语言的能力啊,这时候呢,就开发了一个当前产生的一个本地方法站,本地方法站呢,他通过通过本地库的一个结口啊来执行第三方语言的 迅捷站呢,他能在我们执行方法的过程中啊,当前要保存当前方法的一些局部变量,包括方法的进站、出站等一系列信息啊,因此啊,这个呢就成为一个动态的, 动态的方法执行的一个模型,内存的一个模型。那么接下来就是一个加瓦堆,这个堆空间呢,它是 g v m 组成部最大的一个空间,这个空间呢,当我们 的对象都大部分都存在这个内存区域了,因此这一部分也是一个 gc 的重点的回收的一个区域,也是我们学习的一个重点区域。 ok, 我们在具体的堆章节来再对他进行详细的讲解。 程序寄出去呢,这是我们一节要学习的内容。程序寄出去呢,他也是一块 jbm 的内存区,他这个在这个内存区啊,最小的一块, 这个程序是做什么用的?当我们的这个字解码执行过程中啊,从上到下在执行过程中,他能专门开辟一个空间来从这个每一个县城的字解码执行的这种字解码地址, 也就是我们所说的这种这种行号,这种行号呢就保证我们程序啊从上到下是按顺序执行的, 这个执行过程中啊是通过执行引擎啊来进行驱动的,当执行引擎执行,比如是第七行的这个指令,他首先呢从这种 程序计数器里面取出这种字解码地址,这个同时呢取走之后啊,这个字解码地址啊立即就会变,就会加,加就变成比如七,他就会变成八。取出之后呢找到这个七的地址之后啊,把这个指令啊加载到我们结尾母 来转换来进行执行,执行之后呢下次就变成八了,他在执行下一行做,他再继续取取这种 接程序计数器的这个字解码地址,按照这个顺序啊,直到这个程序啊被执行完,这呢就是我们所说的这种程序计数器的,他也是一个内存的一个区,他比较小,因为他只记录这种一个字解码地址的 英塔台也是一个非常重要的一个区域, g、 v、 m 的, 那么呢我们通过演示一下,就是这个字解码如何产生的。然后接下来就理解我们对这种程序计数器这个过程呢有一个比较深的理解,那么呢我们先操作一下, 我现在呢准备了一个 类,这个类呢叫 p、 c、 r, 它有两个属性,有两个属性, 同时呢这里面呢还有一个方法,这个方法这就是我们原码,这个原码呢就是在我们的 语言过程中啊,编译好之后啊,我们的原码转换成一个字节码,他呢有按照这种 gvm 的一个规范,他呢会有一个 跟当前这个原码是不一样的了。那么呢我们现在来看一下我们手动的,通过我们手动来编一下这个原文件, 首先呢我们把 这个原文件编一层字解码文件, 那么下面呢就产生一个字解码 class 文件,这个 class 文件呢我们当前呢是可以通过记事本打开,我们看一下它的内容, ok, 这个内容呢我们似乎看不懂,它前面呢都是一个 十六进字的,这十六进字呢,其实啊在计算机里面它是有规则的,这些规则啊是按照 g v m 的一个规划来定义的,我们为了能看懂啊,我们通过一个指令啊,通过指令 加 r p 这个紫莲红,看一下它是一个什么样的内容, ok, 这样我们就把它反向编辑出来了,这过程中呢前面呢 code 呢是我们的一个 属性信息,下面呢就是我们的一个方法,这个方法呢就是我们当前的一个字解码文件,就刚才那几行 累加一下,然后接下来就产生这些,这些呢是在肺边缘之上的,也就是这呢是只有 j v m 能够把它识别出来执行, j v m 呢 还能再把它转换成费边缘来调度到 cpu 资源里面,不同的 cpu 资源那个价比如差 八六的来进行执行的。这里面呢他都是有这种行号,这个行号呢就是我们称作他为字解码地址,这个字解码地址在执行过程中解封,执行过程中这种就会把它加载到我们的程序计数器里面, 程序计数器呢就专门记录这一行哈,随着他们执行啊不断的进行累加,不断的累加就保证我们当前程序啊,保证我们当前程序啊能够从上到下不会遗漏的来进行执行。 这个字键码呢,大家能够理解知道一下,这个对我们 j v m 执行过程中啊,也是一个,也是一个知识点。那么我们再看一下 j v m 的一个功能特点, 那我们的切换到我们当前的 b g 里面, 然后他哪有哪些这种功能特点呢?这个功能特点呢?在我们面 面试或者是其他可能会问的到,因此大家一定要理解这些概念。您理解这之后啊,我们当前在市场的面试啊,这样呢就可以轻松的应付过去 县城的隔离性。这个怎么理解呢?指的是我们这个,指的是这个程序技术下,他呢是一个私有的内存供应,是以私有的,这私有怎么理解呢?就是当我们开启一个县城的时候, t 一和 t 二, t 一 呢,这时候呢就程序计数器里面开一个内存空间,这个内存空间呢,他完全是私有的,比如 t 一开的内存空间和 t 二开的内存空间,他们呢像素啊,他们是不访问的,是不共享的, t e 只能用 t e 的,天热只能用天热的就保存。我们的县城啊,私有化具有一定的隔离性,保证这个多县城在并发过程中啊,不会被对这个变量的一个破坏而引发这种严重的问题啊。因此啊,我们要理解这种 程序计数器,他这个内存据啊是稀有的,在任何线程啊,他们之间都不会共享这个变量信息,占用的内存比较小,我们在讲 概论的时候已经讲过了,他呢只保存当前这个字解码的一个地址,其实就是一个行号,这个行号呢一般都是比较小的,因此啊,他占用内存空间是非常小的, 同时呢它不会产生这种 o o m 这种异常,因为它的内存占的是足够小,可以忽略不计。 然后这个字解码地址呢,刚才在这里面已经讲述过了,然后这个 native 呢,就是刚才讲的就是本地方法, 当执行本地这个滴滴儿时候呢,或者是本地 c c 加加库来进行实现的。我们这个 native 啊,它的执行过程中啊,它是从 c 和 c 加加来进行实现,不是非加瓦自解码 就不是这种字节嘛,因此啊,它这里面是为空的,它是在 j y 非 j y, 在 j y y 的内存空间啊来进行执行的, ok, j v m 呢,大家能够知道这些概念,知道它就是保存这种字解码,就是我们现成的执行过程中啊,保存这个字解码地址的,然后它的内存空间占用的比较小等一系列这一部分搞清楚了, 这呢我们在面试的时候啊,就可以游刃而有余了,同时呢也可以理解我们当年 j v m 执行过程中的一个整体的一个过程。 ok, 这节呢我们就讲到这里,谢谢。

看下我们的方法区,我们方法区可以看这是一块独立于我们家瓦堆的内存空间,方法区还有一个别名叫飞堆,目的是要和我们的堆分开。再看下我们方法区的作用,它是用来存储我们内信息常量值,静态变量以及我们 git 变异后的一个代码等数据。 我们方法区是所有现成共享的内存,在加我八以前,我们是放在我们的 gvm 内存中,由我们永久待实现,是我们 gvm 内存大小参数的一个限制, 因为我们方法区在实现,在我们加瓦八中做了一次大革新,在加瓦八中我们移出了永久带的内容,方法区由我们圆空间实现,并且直接放到我们的本地内存中, 不是我们 gvm 参数的一个限制。当然,如果说我们物理内存也被占满了,那么方法区他也会爆我们的 om, 并且将原来方法区的支付算常量,还有我们的静态变量都转移到了我们的 java 堆中。我们方法区它在我们 g v m 启动时候被创建,那么我们关闭,我们 g v m 就会释放这个区域的内存。同样的,我们方法区也会抛出我们的内存溢出,那比方说我们加载了大量第三方的价包, 或者说我们 top cat 部署的工程过多,都可能导致我们的一个方法区溢出。好,这就是我们的一个方法区的介绍。

面试题, java 虚拟机 jvm 的运行时数据区是如何划分的?哈喽,大家好,我是架构师奶爸。 java 虚拟机 jvm 的运行时数据区主要分为以下几个部分, 一、 java 对 e 这是 j b m 所管理的最大一块内存区域,几乎所有的对象实力都在这里分配内存。 java 堆是垃圾收集器 garbage collector 的主要管理区域,可以被所有县城共享堆内存区域不全是县城安全的。 一些特定类型的对象,如 final 修饰的或者锁定的对象会被分配到方法区或其他县城安全的地方。二、方法区 method area 方法区时存放已被加载的类信息、常亮、静态变亮以 以及及时编译器编译后的代码等数据。方法区的内存回收目标主要针对常量池的回收和对类型的卸载。三、占 stack jvm 中的每个县城都包含一个私有的战,用于存储方法调用和局部变量。每个方法调用都会创建一个战争,用于存储该方法的局部变量, 操作数战和方法出口信息。每个县城在任何时候都只有一个战争,处于活动状态。四、程序计数器 program counter register 这是一个较小的内存区域, 可以看作是当前县城所执行的自解码的行号指示器。自解码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的自解码指令。五、本地方 法站 native method stack 与 java 堆站类似,本地方法站用于支持 native 方法的执行。以上就是 j v m 运行时数据区的主要划分,需要注意的是, 具体的内存区划分可能会因不同的 j、 b、 m 实现有所差异。以上是一种常见的划分方式,想了解更多 java 架构师岗位知识,请关注我,架构师奶爸共同筑基 java 架构师。

今天我们一起来聊一下大家对于 gm 运行时的内存区域的一些理解。上图应该都很熟悉,他就是 gm 运行时的数据区域,里面有方法区啊,堆啊,站啊的这些我就不细讲了,主要是这些在书上啊,网上啊一查一大堆,其实都说的很清楚。 接下来我想说的是本地内存和直接内存,即我们常说的堆外内存,如果把它们和这个运行式数据区域放在一块看的话,你还搞得清楚吗? 比如上图的这个图,我们来想象一下这个直接内存,或者说这个堆外内存它是一个什么样的存在呢?和这个堆内存之间去比较的话,又是什么区别呢?接下来我们来一个一个聊聊。 首先我们如上图的第一部分,我们先来看一下 g u m 它是个什么呢?它是一个由 c 加加编写的 c p p 文件嘛,对吧? 然后启动以后呢,他就变成了一个 c 加加进程,就是相当于 g m 的这部分 c 加代码在操作系统上面跑了起来。 然后呢,在 linux 系统中呢,每一个进程呢,他都会有一个进程的虚拟地址空间,这个是操作系统给进程对应分配的一个空间,他主要表示这个进程中一些数据区域的划分 背后对应的就是我们真实的物理内存了。当然这中间还有页表什么的我没有画出来,这里只是一个简图,感兴趣的可以自己去再了解一下。这里呢,我们只需要记住 gum 进程呢,它对应有一块自己的内存地址空间。然后呢我们再回到第二部分,看 这个我们加瓦运行时的内存区域呢,就相当于 g u m 这个 c 加加进程在启动的时候,向 这个虚拟内存空间申请了一部分内存,然后把这幅内内存根据嘉瓦运行时的需要划分成了方法区啊,堆啊,站啊这些区域,然后由 gvm 进行管理。 大家可以想一下 gm 代码写的思路大概就是然后调用 c 加加的申请内存,申请一块完整的内存,然后根据代码逻辑上进行对他一些划分和管理,分成不同的对压站啊, 这就是我们常谈的 gum 运行时的内存区域,它就是这么来的,你现在大概脑子里有一个印象了吗?接下来我们再看一下直接内存,其实网上有两个概念,一个直接内存,一个本地内存,其实这里呢本地内存它是一个总称, 直接内存是本地内存的一种直线方式,所以我们直接来弹直接内存就好了,他也就是我们常说 的堆外内存,因为他不在运行时内存区域的堆中这块区域是 gum 怎么申请的呢?我们看一下我紫色框出来的这部分区域, 它呢是 g m 底层申请的时候呢,最终调用的可能是 molec new 或者 m map 这种函数去向虚拟地址空间申请的一块内存区域,然后 还有我们堆上的这个 direct bet buffer 来把它引用起来,这个就是堆外内存,我们可以想一下,对吧?它是完全独立于 gm 运行时区域的,接下来我们再区分一下这两个区域的一个区别。 加瓦运行式内存区域呢,是 gum 向虚拟地址空间申请的一块内存,并且根据我们加瓦的需要把它划分成了堆占,这些区域由 gm 管理,是 gum 讯机规范中定义的内存区域。而直接内存呢,它也是我们的 gm 进程向自己的内存虚拟地址空间申请的一些区域,它被常用作一些 nio 的操作, 他不是加瓦逊及规范中定义的内存,通过上图我们可以明显的看出来,他是独立于加瓦运行时区域的一块内存。 这个视频呢,我们就想讨论一下,加瓦运行时内存区域他是怎么来的,以及呢?这个对外内存,我们常说的本地内存之间内存的关系,以及他又是怎么来的,和我们这个运行时内存区域的一个关系,现在你清楚了吗?如果觉得有什么地方说的不对的,欢迎指出。

首先这个刚才咱们说了,县城共享区域这块的话,主要由两大部分来组成的,一部分是这个方法区,一部分呢是这个加瓦堆啊,也就是堆空间这一部分,哎呀,喝口水啊, 那方法区呢?我们今天讲的这个 jdj 版本的话是八,也就是一点八这一块, gda 一点八的话,他是有一和 gda 之前和 gdaa 一点八之上, gda 八以前他有一个,有一个,这个对方法区有一个命名上的一个区别就是什么呢? gda 一点八 以上,我们对这个斑马区呢,我们又称之为是圆空间,然后 gdk 一点 七,包括 gdp 一点七,他之前的版本呢,我们方法就我们又称之为是永久代, 永久干。然后方法区我们主要存储的一些对象或者是一些信息的话,主要是存储的这个像啊类信息类的信息,比如说 hello, word 点卡死这个信息的话,也是存放在我们的方法区内的,像一些长量 static, 对吧?这些信息的话也是存放在啊,不是翻的敞亮,我们这些敞亮的话也是存放在我们的这个方法区。将一个镜来变亮也是存在,也就是 static 这信息的话也是存在我们的方法区内的。另外还存放的信息是包括这个 及时编译,七编译后的这个代码同样也是存在我们的方法区的。 那有一个问题就来了啊,大家在记这些,因为像 gm, 你看我们刚才从头到尾讲的这些,现在讲的是第七页这个 ppt。 什么是宝马区呢?记得概念特别多,那方法区这个概念的话,大家可以这么去想一下,去记的这个概念就是方法区, 方法,就因为他存放的一些信息大部分都是一些类的信息,那类点 class 里面都都是由基本上都是由方法来组成的,你比方说慢方吧,是吧? 我们做一些测试的时候,慢方人必不可少的一个入口方法吧,对不对?慢方法秒让我们写一个 add 方法,写一个 mouth, 是不是写一个查询方法,写意思压力 的一些方法都是由我们的类信息,我们的所有的类都是由方法和一些基本的一些属性,或者是一些运营运运行的一些逻辑来组成的,那这些信息的话又是存账在怎么呢?我们的方法去,所以呢, 我们可以很直观的理解为把他这个去记为这个方法区,是比较容易去理解这个概念的。 那什么是堆呢?堆又是一个概念,是不是?方法就一个概念,堆一个概念,那堆是什么呢?我们所创建的所有的,哦不,这个对象的话,我们装做对象创建的对象都是存放在我们的堆里面的, 对,也是咱们大家需要重点关注的一个区域啊,因为这个里面的话涉及到是 什么呢?内存的一些分配啊,像我们要创建一些对象啊,你有一个关键字啊,或者是什么的,如果大家觉得这个没有对象不太好使的话,我们也可以通过反射的方式把我们的对象给创建出来,这样的话效率会更高,对不对? 假如大家在线的这个朋友们没有对象呢?或者没有男朋友的,没有没有女朋友的,大家都可以通过咱们那个加法程序,然后你有一个,你有个女朋友, 不过按照咱们中国的这个法例来说的话,不要你有太多了啊,你有一个就够了,你有多的话就违法了。 那这块区域的话,同样是一个是涉及到咱们那个堆这块的话,一 测试涉及到咱们这个内存的一个分配,也就是对象的创建,还有另外还会涉及到什么呢?就是他的回收这一块,回收里面呢?又涉及到这个什么呢?回收我们所用的一些算法,还有我们用到的一些搜集器都有哪些,对不对? 是不是这些东西都是在堆空间里面是比较重要的一个内容,也就是说他所今天我们着重会去讲的一些内容, 所以说几乎我们所创建的所有的对象的话,都是在咱们的堆中进行分配的。 另外这个加啊,这个堆这一块的话,又涉及到了几个重要的参数,就是说像第一个参数 xms, 他比 表示的意思是什么呢?他表的就是最小堆空间是多大?像我们的应用程序的话,我们的为服务的话,每一个服务标准化是四个 g, 就是四零二四,四零二四造。 那第二个参数的话就是 xmx, 也就是说最大对空间是多少, 这个参数的话,同一般情况下我们会把这个 xmx 和 xmx, 也就是说最大堆空间和这个最小堆空间,我们会把它给设置的是相等大小。 为什么是这么设计呢?因为就是说白了就是什么呢? 你创建的对象,你说,所以说第三个参数也就诞生了,就是 xmn 这个参数,这个参数的话就是代表了什么呢?你的堆空间,无论你的最大值和最小值, 我都直接就是说用这一个值来给你代表了,就是 xm 直接就等于四个 g, 我给你就分四个 g, 你的最最大值最小的都是四个 g 啊,他就是前面这两个参数的一个,呃,一个合并了,你可以理解为是一个合并。 那问题就来了,我们的县城共享这块区域的话,为什么? gm 或者是说现代欧瑞口公司吗?以前最早的时候是要散公司,散公司来维护, 在维护咱们的这个 gdk, 现在的话是欧瑞狗把散公司给收购以后呢?是,呃,对,他就是欧瑞狗公司的了吗?所以就欧瑞狗公司就从这个一点八开始就已经开始维护了, 那我们就可以选啊,那他当时上公司是为什么会把这个县城共享这块区域给划分为方法区和加瓦堆?你直接用一块内存或者空间来代替不就完了吗?为什么要分这么详细干嘛? 我们可以反过来去再去想一下这个问题啊,因为方法七存放的信息是什么呢?你们可以大家可以看一下敞亮订单变量内信息,什么便衣后置代码,这些东西的话 基本上就是什么呢?不变的,就像你个人似的,你有眼睛、鼻子、嘴、头发、 耳朵,那这东西的话你还会再增加其他的吗?对不对?你一个脑袋瓜子或者是身上你有两只手,你不可能多出来三只手吧?对不对?这些信息的话说白了就是不变的, 不变的他是不变化的。然后我们堆存放的信息呢?我们堆存放的信息都是我们创建了一堆的对象,对不对?对象一、对象二、对象三、对象四,所以创建了一堆对象,我们称之为堆,而且这些数据呢是变化的, 对不对?我们可能创建一、创建二、创建三,创建四、创建五,然后创建一对象 a 对象的话,他可能是原来是等于一,后来呢有可能是变成二,那他所存放的数据呢?是变化的,所以呢他这样划分的原因呢?就是把这个变化的数据和 不变化的数据呢,我们做一下区分。也就是说像我们如果做过架构的,或者是了解过 ngnx, 就是说比较运煤那块维护的,经常维护的一些东西的话,有一个概念就是什么动静分离,动静分离, 对吧?也就是说有一这么一个概念,哎,你搁这一块的话有一个概念是什么?我这里面写了一个东西,就是什么动静分离、实战动静分离。所谓什么是动静分离呢?就是静态和动态是吧?就是说 像我们前端写的一些静态页面是吧?和我们这些东西的话,我们可以称之为静,也就是说基本上你像前段的一些那个图片呀、文案啊,或者按 按钮啊,这些东西都基本上是不变化的。像 jbg 啊、 gs 啊这些文件的话,都是我们可以通过缓存啊,或者是呃 这东西来做一些加速啊,还有后台的一些动态化,像数据的一些查询啊,前段页面,你比如说我展现的这个列表,可能是有一月、二月、三月、四月、五月,然后这样动态变化的这种。 还有你比方说我的金额,我个人信息里面有个人金额,是不是个人金额?我可能今天是一块,明天是五块。你比方说抖音直播号我的钱袋里面的,原来今天是一块,然后我直播完了是变成两块了, 对不对?那这些数据的话都是通过后端的一些微服务或者是一些服务,或者是一个查询来完成的。那这些数据的话,我们把这块的业务呢进行分开, 是吧?你前段你写你的后端,由我来完成我们这些做加瓦的,或者是写后端服务的这种服务做,我给你做服务支撑,然后完成咱们整个项目体系的一个结构体现,这样的话我就我们可以简单理解为是动态 动静分离,动静分离,对吧?动静分离那啊?再回到 gm 这块,这个共享区域这块,他也是为了这个,他也是为了这个概念,对不对? 好,我们把这两个东西的话了解完以后,我们先对这个共享区域,县城共享的这块区域的话,大概大家先有一个概念,或者说有一个印象 啊。然后呢我们再回过来头,我们先再看一下这个县城私有这一块。县城私有这一块的话 里面呢?因为我们刚才也说了,他每一个县城里面的话都有三部分组成,一部分是程序记录器, 一部分的话是那个本地方马站,还有一部分的话是那个虚拟记站,这三部分,对不对?我们首先来看一下这个县城私有里面的这个程序技术器, 那什么是我们还是得回到这个概念上,对不对?现在你看讲这么多的话,基本上都是在讲这个概念或者什么的,这个东西其实面试官到时候问的时候也会问你这样的问题,就像刚才这个说的是,为什么这样划分呢?对不对?你光了解这两个 概念了,你为什么要这么花瓣呢?你得了解这个作者,或者说这个散公司这里面的这个作者,他人家这些人,哦,这些人的话去写这些代码的时候,或者是做这样的的空间,人家为什么去这么搞,对不对?你了解人家的思想的时候,你在实际工作当中,你在做你的项目设计的时候, 你同样也可以这么去搞,是不是?我到时候也搞重金分离,对不对?我也是不是也可以这么搞啊?我加往堆里面,我也可以给他设置一堆参数,我也可以给他做一些这个反色, 提供一些反射机制,没有机制或者是回收机制,利用一些犯法创建不同的这个收集器,我们都可以这么玩,是不是? 所以呢?我们这个县城私有程序记录器,首先我们也了解一下程序记录器呢?他是唯一不会 产生这个 om 的问题的,对不对?大家有没有什么是 om? 是不是?内存异租对不对? out of the memory arrow 对不对? om 错误,他是唯一不会产生这个。呃, vom 的 程序记录器呢?就是指的是什么呢?指向当前正在执行的,也就是当前县城你正在执行的这个字节码的一个指令的地址,或者是我们称之为是行号, 是吧?他就是指向一个位置的。我们假如我现在给大家讲课,然后 我起了一个县城,然后我跟大家互动聊天,我又起了个县城,现我们称之为是县城二吧,那么这时候呢?我现在给大家讲课呢,突然间有个学生问我了,哎,许大人, 那个您那个东西的话对我们有什么帮助呢? 是不?我看到大家那个咱们的家人给我们讲问题,问这样的问题,我是不是应该很有礼貌的给给徐大人,或者是说这位粉粉丝,然后回复一下, 然后啊这个东西是为了我们可以更好的写代码,然后应付面试,或者说提升我们的这个分析问题或者排查问题的一些能力,是不是?我应该给人家解答一下,等我解答完了以后呢? 我解答完了以后我解,我解答完以后,是不是我应该再回到我这个讲课的这个上面来,我应该再回到我的讲课里面,那这时候呢?这个成语记记录器呢?就会 回到通过这个程序记录器,我们会回到刚才的现成一,继续我们刚才的讲课,也就是说记录我们这个现成的一个执行的一个进度, 对不对?我们得知道我们刚才现成一讲到哪里了?我刚才讲的 ppt 是讲到第八页了,对不对?我们讲到这个第八页了,讲到程序进入记这一块了,那是不是我就要,就要同学聚会就会告诉我啊?你只讲到这里了,你可以回到这里,然后给你们的这个家人 或者是粉丝们继续讲这块的信息就可以了。哎,是不是他就是起到一个这样的作用,因为我们使用的电脑,因为我们的程序是一运行在这个操作系统上面的,操作系统上面的所有的 他的 cpu 在运行的时候,他是一个多现成的一个状态, 他不是有一个人在干活,对不对?他不是有你现在像八盒的操作系统,是不是?他不是有一个人在干活的?他是有一个先等一,先等二,先等三,先等四,先等五,可能有好多个,三百个或者几十个这样的一个量,然后在里面,并且他是没有规律的, 他没有任何规律的,对不对?你有在先,有在前面的,也有在后面的,或者是后面去执行的,那这些东西的话, 我们就这时候就需要有一个东西来什么呢?我们就需要每个县城过程当中,每个县城,而且在运行的过程当中呢,他是有可能会发生中断的, 对不对?他不可能是一直是行的,就像那刚才我说说的一个讲课现场,一个是聊天的一个现场, 那这两个县城的话,我不可能一直在跟大家聊天,那我就不用讲课了,对不对?所以呢我中间这个聊天的过程可能会中断,然后我继续我的讲课过程,所以他意味着是什么呢?意味着这个县城过程当中我还会进行一个县城一和县城二的这样的一个切换, 那么我们就是为了保证这个多线程情况下这个程序的一个正常运行,这个时候我们就 所以说程序记录器就起到了他的一个至关重要的一个作用,也就是说这个时候他的作用就来了,他就是保证我们这个县城多县城的这个情况下,这个所有的应用程序他的一个正常执行 啊,防止我们的操作系统出现一个乱搞的一个情况,对不对?我可能现成完现成二,由现成二去切换,到我们现成一的时候呢? 我本来是讲的第八页,他给我指到一个第九页,是不是我跑到个第九页,那是不是就会出现这个程序乱搞,或者是操作系统乱搞,然后搞自我的,导致我的应用程序出现混乱或者是错乱呀?我就不知道我的问题,我的这个东西到底 进行到哪里了?我都不知道我的进行哪里了,插下电源是吧? 所以呢程序技术器为什么需要程序技术器呢?程序技术器就是在就是因为我们的家瓦是多现成的,然后呢? 在程序运行的过程当中就会有一个县城和县城之间的一个切换,然后我们来确保我们的家瓦应用成绩,在多县城的情况下, 一个每一个程序,每一个应用程序的一个正常执行,这就是我们 需程序记录器的一个作用啊。回过头来我们再看一下他的概念就是什么呢?他就是指向我们当前线程 正常执行的这个质检码指令的一个地址或者是行号。行, 我们看一个代码,这个代码的话就是是你比方这个普森类,我这里有一个普森类啊, plus 类的话,我们看一下他的大字结构,这个结构里面就是有一个沃可的一个方法,有一个慢函数, 那程序技术具就是什么意思呢?你比方说我们这个代码有第十行、第十一行、第十二行、第十三行、第十四行,是吧?一直到我们的二十一行,那我们程序首先执行的时候是执行哪里呢?是执行的我们的慢函数, 然后慢函数是从啊十八行、十九行执行到第十八行啊,十九行啊,对,就是这样的一个过程,对不对? 他就相当于我们的十八、十九、十七、十十六、十五、十四、十二这样的一个概念,就是指的我们的一个代码的一行号,或者是字节码指令地址的一个行号。 我们要是再想更深入的看一下,我们可以看一下你比如说他所谓的自检码吗?对不对?我们可以看一下他的编译信息, 我们看一下边这就是他的卡拉斯文件,我们通过一个命令。行,我们来看一下,我们前面讲到了一个概念是什么呢?就是我们加提议结构里面有一个命令,就是加 p, 这个加 p 的这个命 就是反编译,也就是说我们通过这个命令就可以查看我们的某一个卡死文件的一个字节码的一个相关信息。 ap 杠飞杠拍死。好,这个星期的话,大家可以看到其中有一部分,你看这个 扣的,这就是沃克方法,沃克方法前面的零一二三四五六七八九十十一十二,是吧?这个就是字节码的地址或者是行号 啊。行,看完这个的话,我们再回到我们的 ppt, 这就是我们刚才讲的这个程序技术器,大家对这块的知识有都清楚了吧?如果要是清楚的话,大家可以在平台上扣一,不清楚的话可以扣二,我再给大家简单的描述一下。 好,大家没有说的话,那我就接着往下讲了,我们再讲一下这就是我们的程序接触器,然后,然后我们再回过头来就是说再看一下他也有虚拟基站,县城私有这块的话,第二部分就是虚拟基站, 首先我们来了解一下什么是站?站的一个数结构是什么样子呢?是不是虚拟记站首先有站,大家都知道站是什么吗? 我右手边这块图呢是一个水杯的一个形状,水杯的形状,而且你看这个水杯呢是你的倒水也好,你喝水也好,你都只有一个口,没有第二口,下边是封的,对不对? 另外的话,我们现在左右左边的话有 a 方法、 b 方法和 c 方法,箭头的意思是表示什么呢?我们呢 a 方法调用 b 方法,然后呢? b 方法调用我们的 c 方法, 站的数据结构就是什么呢?我们的假如我们的 a 方法调用 b 方法和 c 方法,他的执行过程就是这样子的,哎,我调用我的 a 方法, a 方法,然后呢? a 方法调用我, 我们的 b 方法好,然后 b 方法呢?又调用我们的 c 方法,他就是这样的一个过程,然后 a 方法是在最下面,然后 b 方法是在中间的位置,然后 c 方法在我们的最上面。 当他那个执行的过程当中,他就会有一个出战的一个过程,就是说 c 方法是先出来的, 然后就是相当于你喝水似的,你的水是你最后倒进去的,水都还是在至于上面的,假如我们不考虑水的这个流动性的问题的话,那你最上面倒, 最后倒出来,倒出去的话,他肯定是在最上面的,也就是 c 方码肯定是在最上面的,那他出来的时候呢?因为你只有一个出口,你的入口和出口只有一个,所以呢他也是 c 方码是最先出来的, 然后呢 b 方法也是他是紧随其后,然后就是第二个出来,然后 a 方法的话是 最后一个出来,对不对?这就是他进的时候呢,他的一个顺序就是 a、 b、 c 的一个过程,也就是 ppt 上写的他就是一个 a 调 bb 调 c 就是 abc 这样的一个过程。当他出来的时候呢,他的过程是一个 cc 先出来,然后 b 紧跟其后,然后 a 是最后一个出来, 然后,呃,这两个操作的话,我们分别称之为是什么呢?入战,入战的一个状态就是 abc, 然后第二个动作呢,出来的时候呢,就是一个出站,我们称之为出来的这个动作呢,我们称为出站,也就是 cba 这样的一个顺序。 所以呢赞的一个数据结构呢,就是他的就是出口和入口是只有一个,另外他也有两个动作,就是刚才咱们所说的这两个动作,就是一个出站,一个入站这两个动作。 通过这两个点呢,我们就可以分析出来呢站他的有一个特点就是什么呢? 先进先出的这样的一个特点,嗯? last the oat 对不对?先进先出,好,先进先出,大家是不是可以看出来他就是一个先进先出的一个过程,是不是?然后我们把这个 bt 还原一下啊?他就是一个这样的过程。 那我们又问题又来了啊,大家可以思考一下为,那为什么他要用赞呢?对不对? 为什么方法执行的时候我们要用战这种概念呢?你看我们的 a 方法, b 方法、 c 方法,是不是他出战,入战是不是都是要用战的这种结构呢?战的这种数据结构呢? 有没有人知道这个问题?因为什么呢?因为我们的方法在执行的过程当中呢?其实与站的这种数据结构的这种执行特点是相当的吻合的,对不对? 所以呢,我们在调用方法的时候,我们的方法在执行过程当中才会用赞这种数据结构来进行处理, 用战这种结结构进行处理,就跟咱们那个在大街上遇到那个漂亮的姑娘或者是美女的时候一样,哎, 这姑娘的这个生辰八字的话,跟跟跟我很相似呀,是不是?嘿,这就是咱们这个训一战这个这个特点, 这个特点是不是就像咱们这个执行这个方法似的?你看这个沃可这个方法,我先执行第一行,再执行第二行,再执行第三行,再执行第四行,是不是这样一个顺序?最后然后再返回,是不是这么一个过程? 他的所以说我们的所有的执行方法,就是说加瓦的纪委按摩里面所有执行的方法的话,都是通过这个站的这种模式,他跟他的数据结构的特点都是相当吻合的,所以说我们才会采用这种方式来进行执行,对吧? 那虚拟记赞的话,同样的现在你看到这个 app 呢,就会又涉及到很多概念,真赞,是不是又看到了这种很多的这种像这种什么什么 哎呀妈呀,什么局部变量呀?什么操作出战呀,动态连接呀,返回地址啊,噼里啪啦又一。


这个问题呢,其实很多小伙伴在去面试的时候,经常会被问到这位 m 内存结构,这位 m 他到底是如何划分内存的呢?在这位 m 信息中,这位 m 对于计算机内存的划分以及管理,在网上去找,你会发现网上普遍流传的这边 m 内存结构的这个图 都不是特别严谨,今天我就把我自己珍藏的 j v m 结构图分享给大家,接下来我帮大家解析一下这个图。这个 m 内存结构图中,它主要是有两部分内存区域, 一部分呢叫做堆,另一部分呢叫做债。我们方法执行的时候,他是一个进站出站的过程,然后在站当中呢,也有一个迅息站和本地方法站,在迅息站当中呢,他 主要存储的是方法局部变量和我们运算过程当中的数据,在本地方法占当中,他存储的是我们内存方法, 也就是吊用的底层,底层指的就是操作系统底层的一些原声的裤堆。内层当中呢,我们一般扭出来的对象都放在堆当中,我们也会看到一些比如新生代、老年代的空间, 这些内存的区域是基于分代收集理论设计的方法区,他存储的是我们虚拟机加载后的 clus 字节码静态变量常亮常亮池。 那么我在这里边给大家讲解了这个禁止的是交了吧,交了的后期版本,这个内存的区域也是会发生一些变化的,但是我们现在在市面上主要流行的还是 gdk 一点八。

哈喽,大家好,我是专注加瓦干货分享的灰灰 gm 内存结构都有什么分别?有什么用?前几天啊,我一个有四年开发经验的粉丝,就因为没有答上来这道题,错失了一个三十岁的 offer。 如果你也不清楚这道题要怎么答,建议花两分钟时间看一下。 另外,我还准备了一份加瓦程序学习路线图和能力模型图,里面详细的介绍了小白到架构师的完整路径以及每一个阶段应该掌握的知识点,有需要的小伙伴可以在评论区扣六六六领取。 gm 的内存结构我们可以分为现成更详的和现成独享的两大块来区分。现成独有的有程序计数器。 程序计数器呢,它是一个很小的内存区域,它保存了当前县城执行的自建码指令的地址。在多县城的环境下,每个县城都有自己独立的程序计数器,它的作用呢,主要是指当前县城的执行位置,以实现县城切换和恢复。本地 方法站,本地方法站用于执行本地的方法,这些方法是本地编程语言如 cc 加加编写的,并通过 gmi 与加法代码交互。那本地方法站呢?负责管理本地方法的调用和执行。虚拟基站,虚拟基站用于保存每个方法的调用的战争,它包含局部变量表 操作速载和指向运行时常量池的引用,用于执行方法调用和方法返回的操作。那么上面呢,都是属于现成独享的,那么现成共享的包括堆加法堆呢?是 gvm 中最大的一个内存区域, 于存储对象实力非内存啊,是用于动态分配和管理对象,他在运行时自动进行垃圾回收,以释放不再使用的对象。方法区方法区啊用于存储类的结构信息、常量、静态变量、方法字解码等等。它包含类信息和原数据,是所有现成共享的,用于支持 内加载和运行反射等功能。对外内存对外内存不是 gm 内存的一部分,但是它是加了应用程序可以访问的内存,通常由操作系统管理。对外内存用于存储直接内存、缓存区、文件、 io、 网络数据等等。 通常在需要更多控制内存分配和释放的情况下使用。今天的内容啊就分享到这里,如果对你有帮助的话,记得一键三连。我是灰灰,我们下期再见!

面试题, j v m 堆内存分配机制是什么?哈喽大家好,我是架构师奶爸在 java 中创建对象的时候,对象是在堆内存中创建的,但堆内存又分为新生代和老年代, 新生代又细分 eden 空间, from survivor 空间就 survivor 空间,我们创建的类到底在哪里?一、对象优先在 eden 区分配 堆内存分为新生代和老年代,新生代是用于存放使用后准备被回收的对象,老年代是用于存放生命周期比较长的对象。 大部分我们创建的对象都属于生命周期比较短的,所以会存放在新生代。新生代又细分一等空间 from survivor 空间 to survivor 空间我们 创建的对象,对象优先在 eden 分配。随着对象的创建, eden 剩余内存空间越来越少,就会触发 minor gc, 于是 eden 的存活对象会放入 from survivor 空间。 minor gc 后,新对象依然会往 eden 分配。 eden 剩余内存空间越来越少,又会触发 minor gc, 于是 eden 和 from survivor 的存活对象会放入 to survivor 空间。二、大对象直接进入老年代在上面的流程中,如果一个对象很大,一直在 survivor 空间复制来复制去,那很费性能, 所以这些大对象直接进入老年代。可以用 x x pregnant size, fresh old 来设置这些大对象的玉值。三、长期存活的对象将进入老年代在上 上面的流程中,如果一个对象 halloween 已经经历了十五次, minor g c 还存活在 survivor 空间中,那它即将转移到老年代。这个十五可以通过 x x maxtenuring threshold 来设置的,默认是十五。虚拟机为了给对象计算他到底经历了几次 minor g c, 会给每个对象定义了一个对象年龄计数器。如果对象在伊顿中经过第一次 minor g c 后仍然存活, 移动到 survivor 空间,年龄加一,在 survivor 区中美经历过 minor gc 后仍然存活年龄再加一, 年龄到了十五就到了老年代。四、动态年龄判断除了年龄达到 max dangering threshold 的值,还有另外一个方式进入老年代,那就是动态年龄判断。在 survivor 空间中,相同年龄所有对象大小的总和大于 survivor 空间的一半。年龄大于或等于该年龄的对象就可以直接进入老年代。比如 survivor 是一百兆, hello 一和 hello 二都是三岁,且总和超过了五十兆, hello 三十四岁。这个时候这三个对象都将到老年代。五、空间分配担保上面的流程提过,存活的对象都会放入另外一个 survivor 空间。如果这些存活的对象比 survivor 空间还大呢? 整个流程如下,一、 minor g c 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果大于,则发起 minor g c。 二、如果小于,则看 handle promotion failure 有没有设置,如果没有设置,就发起 four g c。 三、如果设置了 handle promotion failure, 则看老年代最大可用的连续空间是否大于立次晋升到老年代对象的平均大小,如果小于就发起 four g c 四如果大于, 发起 minor g c minor g c 后看 survivor 空间是否足够存放存活对象,如果不够 就放入老年代,如果够放就直接存放 survivor 空间,如果老年代都不够放存活对象担保失败。 handle promotion failure 发起 four g c。 想了解更多 java 架构师岗位知识,请关注我,架构师奶爸共同筑基 java 架构师。