11.JDK8内存模型、本地方法栈、虚拟机栈、栈帧结构(局部变量表、操作数栈、方法出口、虚拟机栈与本地方法栈的关系、寄存器、方法区、堆(Heap)、jvm中的常量池、Metaspace(元空间))

11.JDK8内存模型
11.1.本地方法栈(Native Method Stacks)
11.2.虚拟机栈(Java Virtual Machine Stacks)
11.3.栈帧结构
11.3.1.局部变量表
11.3.2.操作数栈
11.3.3.方法出口
11.4.虚拟机栈与本地方法栈的关系
11.5.寄存器(The pc Register)
11.6.方法区(Method Area)
11.7.堆(Heap)
11.8.jvm中的常量池
11.9.Metaspace(元空间)
11.10.堆内存划分

11.JDK8内存模型

本文转自:https://www.jianshu.com/p/44df41ebdbf6

通常谈到JVM的内存模型,一般人会想到堆和栈等,那么堆和栈如何理解呢?
是运行时的单位
是存储的单位
通俗来说解决的是程序如何和运行,数据如何处理的问题;而堆解决的是数据如何存储,存储在哪儿的问题。
在这里插入图片描述
如上图所示,java虚拟机内存模型主要分为以上五个部分,这里以jdk8为学习对象。

11.1.本地方法栈(Native Method Stacks)

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的。其区别在于虚拟机栈为虚拟机执行Java方法所服务,而本地方法栈则是为虚拟机使用到的native方法所服务。

本地方法栈也是一个私有(线程私有)的内存区域,也是后进先出。

虚拟机可以自由实现它,有的虚拟机(如HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常

11.2.虚拟机栈(Java Virtual Machine Stacks)

每个Java线程都有一个私有Java虚拟机栈,与该线程同时创建。

在虚拟机栈内,每个方法会生成一个栈帧。每个栈帧代表一次次的方法调用,一个方法的执行到执行完成的过程,代表栈帧从入栈到出栈的过程。

虚拟机栈会抛出StackOverflowError和OutOfMemoryError。
在这里插入图片描述

11.3.栈帧结构

下图表示了栈帧的组成结构:

11.3.1.局部变量表

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量

11.3.2.操作数栈

操作数栈是一个后入先出的栈。

一个方法刚开始执行时操作数栈是空的,方法执行过程中会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈 / 入栈操作。

例如执行iadd指令时,就会将最接近栈顶的两个int元素取出并相加,然后将相加的结果再入栈。

操作数栈中元素的数据类型必须与字节码指令的序列严格匹配,在编译程序代码的时候,编译器要严格保证这一点。比如刚才的iadd指令,它取出的元素必须是int的,不能出现诸如long和float类型的变量。

虽然概念模型中不同栈帧之间是完全相互独立的,但大多虚拟机实现中会有一些优化处理:令两个栈帧出现一部分重叠,让下面的栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起重叠在一起,这样在进行方法调用时就可以公用一部分数据,无须进行额外的参数复制传递,如图所示:
在这里插入图片描述
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。

静态解析:我们知道Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数,这些符号引用一部分会在类加载阶段或者第一次使用的时候就转化为直接引用,这种转化称为静态解析。

动态链接:除去静态解析的另外一部分将在每一次运行期间转化为直接引用,这部分称为动态链接。

所以要执行某个方法时,某个指令(例如invokevirtual)将常量池中的引用作为参数,而根据这个引用就可以找到真正的栈帧。

关于方法的解析与调用,参考:https://blog.csdn.net/reachwang/article/details/103058653

11.3.3.方法出口

方法出口也可以通俗的理解为方法返回方式:在jvm中,方法返回方式有两种:正常和异常

正常出口:当程序执行遇到方法返回的字节码指令,就完成此次方法执行,并根据调用方指定的返回值返回(可以无返回值)。

异常出口:方法在执行中遇到了异常,并且在方法体内没有得到处理,会导致方法退出,这时候不会有任何返回值给调用方。

程序正常退出时,相当于把当前栈帧出栈,调用pc计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址。

程序异常退出时:当程序发生异常时,返回地址需要通过异常表来确定,在栈帧中没有保存异常表。

11.4.虚拟机栈与本地方法栈的关系

为了更好地理解虚拟机栈和本地方法栈的结构模型以及关系,我们以网上的例子简单描述下,如下图:
在这里插入图片描述

11.5.寄存器(The pc Register)

Java虚拟机可以支持多个线程同时执行,每个Java线程都有其自己的 pc(程序计数器)寄存器。在任何时候,每个Java虚拟机线程都在执行单个方法的代码,即该线程的当前方法。(如果不是native,则该pc寄存器包含当前正在执行的Java虚拟机指令的地址。如果线程当前正在执行的方法是native,则Java虚拟机的pc寄存器值未定义。

pc寄存器中的值就是当前指令所在的内存地址,即returnAddress类型的数据,当线程执行native方法时,pc中的值为undefined。

11.6.方法区(Method Area)

Java虚拟机具有一个在所有Java虚拟机线程之间共享的方法区域。该方法区域类似于常规语言的编译代码的存储区域,或者类似于操作系统过程中的“文本”段。它存储每个类的结构,例如运行时常量池,字段和方法数据,以及方法和构造函数的代码,包括用于类和实例初始化以及接口初始化的特殊方法。

方法区是在虚拟机启动时创建的。尽管方法区在逻辑上是堆的一部分,但是可以选择不进行垃圾回收或压缩。该规范没有规定方法区域的位置或用于管理已编译代码的策略。方法区域可以是固定大小的,或者可以根据计算的需要进行扩展,如果不需要更大的方法区域,则可以缩小。方法区域的内存不必是连续的。

可能抛出OutOfMemoryError异常。

11.7.五、堆(Heap)

Java虚拟机具有一个在所有Java虚拟机线程之间共享的堆。堆是运行时数据区,从中分配所有类实例和数组的内存。

堆是在虚拟机启动时创建的。对象的堆存储由GC(垃圾收集器)回收;对象永远不会显式释放。Java虚拟机可以根据实现者的系统要求选择GC。堆的大小可以是固定的,也可以根据计算要求进行扩展,如果不需要更大的堆,则可以将其收缩。堆的内存不必是连续的。

可能抛出OutOfMemoryError异常。

在jdk1.8之前的版本对内存空间是不同的,主要区别在于:1.8中删除了永久代,新增了元空间。

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过参数来指定元空间的大小。
在这里插入图片描述

11.8.jvm中的常量池

参考文章:https://blog.csdn.net/weixin_40999907/article/details/87907083
方法区:运行时常量池
Class文件:常量池
堆:String常量池

11.9.Metaspace(元空间)

本部分转自:https://blog.csdn.net/universe_ant/article/details/58585854

其实,移除永久代的工作从JDK 1.7就开始了。JDK 1.7中,存储在永久代的部分数据就已经转移到Java Heap或者Native Heap。但永久代仍存在于JDK 1.7中,并没有完全移除,譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了Java heap;类的静态变量(class statics)转移到了Java heap。我们可以通过一段程序来比较JDK 1.6、JDK 1.7与JDK 1.8的区别,以字符串常量为例:

package com.paddx.test.memory;

import java.util.ArrayList;
import java.util.List;

public class StringOomMock {

	static String base = "string";
	
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		for(int i = 0; i < Integer.MAX_VALUE; i++) {
			String str = base + base;
			base = str;
			list.add(str.intern());
		}
	}
	
}

JDK1.6的运行结果:
在这里插入图片描述
JDK1.7的运行结果:
在这里插入图片描述
JDK 1.8的运行结果:
在这里插入图片描述
从上述结果可以看出,JDK 1.6下,会出现“PermGen space”的内存溢出,而在JDK 1.7和JDK 1.8中,会出现堆内存溢出,并且JDK 1.8中参数PermSize和MaxPermSize已经失效。因此,可以大致验证JDK 1.7和JDK 1.8中将字符串常量由永久代转移到堆中,并且JDK 1.8中已经不存在永久代的结论。现在我们来看一看元空间到底是一个什么东西?

JDK1.8对JVM架构的改造将类元数据放到本地内存中,另外,将常量池和静态变量放到Java堆里。HotSpot VM将会为类的元数据明确分配和释放本地内存。在这种架构下,类元信息就突破了原来-XX:MaxPermSize的限制,现在可以使用更多的本地内存。这样就从一定程度上解决了原来在运行时生成大量类造成经常Full GC问题,如运行时使用反射、代理等。所以升级以后Java堆空间可能会增加。

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间的最大区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数指定元空间的大小:

-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对改值进行调整:

-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对改值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。

-XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

除了上面的两个指定大小的选项外,还有两个与GC相关的属性:

-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间导致的垃圾收集器。

-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集。

现在我们在JDK 1.8重新运行一下上面第二部分(PermGen(永久代))的代码,不过这次不再指定PermSize和MaxPermSize。而是制定MetaspaceSize和MaxMetaspaceSize的大小。输出结果如下:
在这里插入图片描述

11.10.堆内存划分

以下转自:https://www.cnblogs.com/cjsblog/p/9850300.html

在JDK1.7以及其前期的JDK版本中,堆内存通常被分为三块区域:Young Generation、Old Generation、Permanent Generation for VM Matedata。
在这里插入图片描述
在JDK1.8中把存放元数据中的永久内存从堆内存中移到了本地内存中,JDK1.8中JVM堆内存结构就变成了如下:
在这里插入图片描述
推统计信息
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《Java核心技术系列:Java虚拟规范(Java SE 8版)》由Oracle官方发布,Java虚拟技术创建人撰写,国内资深Java技术专家翻译。书基于全新Java SE 8,完整且准确地阐述Java虚拟规范,是深度了解Java虚拟和Java语言实现细节的必读之作。   《Java核心技术系列:Java虚拟规范(Java SE 8版)》共分7章。第1章从宏观的角度介绍了Java虚拟与Java的关系及发展历程;第2章概述Java虚拟的整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助;第3章详述如何将Java语言编写的程序转换为Java虚拟指令集,涉及常量局部变量、控制结构、算术运算、参数接收、方法调用、数组、操作数、异常处理、同步与注解等;第4章深入分析用来示编译后的类和接口的class文件格式;第5章定义Java虚拟启动以及类与接口的加载、链接和初始化过程;第6章阐释并列举Java虚拟指令集;第7章提供一张以操作码值为索引的Java虚拟操作码助记符。   《Java核心技术系列:Java虚拟规范(Java SE 8版)》完整而准确地阐释了Java虚拟各方面的细节,围绕Java虚拟整体架构、编译器、class文件格式、加载、链接与初始化、指令集等核心主题对Java虚拟进行全面而深入的分析,深刻揭示Java虚拟的工作原理。同时,书不仅完整地讲述了由Java SE 8所引入的新特性,例如对包含默认实现代码的接口方法所做的调用,还讲述了为支持类型注解及方法参数注解而对class文件格式所做的扩展,并阐明了class文件各属性的含义,以及字节码验证的规则。   《Java核心技术系列:Java虚拟规范(Java SE 8版)》主要内容:   阐释Java虚拟与Java的关系和发展历程。   概览Java虚拟整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据帧、浮点算法、异常等。   详述如何将以Java语言编写的程序转换为Java虚拟指令集,涉及常量局部变量、控制结构、算术运算、参数接收、方法调用、数组、操作数、异常处理、同步与注解等。   深入分析用来示编译后的类和接口的class文件格式,主要包括ClassFile文件结构、描述符、常量、字段、方法、属性、格式检查、代码约束与class文件校验等。   定义Java虚拟启动以及类和接口的加载、链接和初始化过程。   阐释并列举Java虚拟指令集。 【电子版来自互联网,仅供预览及学习交流使用,不可用于商业用途,如有版权问题,请联系删除,支持正版,喜欢的请购买正版书籍: https://item.jd.com/11703581.htmll】
堆、帧、常量方法是Java虚拟的重要概念。 堆是Java虚拟用于存储对象实例的内存域。它是线程共享的,所有线程都可以访问堆的对象。堆的大小可以通过启动参数进行调整。 是Java虚拟用于存储方法调用和局部变量内存域。每个线程都有自己的,用于存储方法调用的信息。的大小是固定的,由虚拟在启动时分配。 帧是的一个元素,用于存储一个方法局部变量操作数、动态链接和方法返回地址等信息。每个方法调用都会创建一个帧,并将其推入常量方法的一部分,用于存储编译期生成的各种字面量和符号引用。它包含了类和接口的常量、字段和方法的符号引用等信息。常量具有动态性,运行期间也可能将新的常量放入方法是Java虚拟用于存储已被加载的类信息、常量、静态变量和即时编译器编译后的代码等数据的内存域。它与堆一样是线程共享的。方法的垃圾收集行为很少出现,主要目标是针对常量的回收和对类型的卸载。 综上所述,堆用于存储对象实例,用于存储方法调用和局部变量帧用于存储方法的信息,常量用于存储字面量和符号引用,方法用于存储类信息、常量和静态变量等数据。 #### 引用[.reference_title] - *1* [11.JDK8内存模型、本地方法虚拟结构局部变量操作数方法出口虚拟与本地方法...](https://blog.csdn.net/toto1297488504/article/details/119701414)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Java,堆,方法常量](https://blog.csdn.net/cafucwxy/article/details/79428677)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涂作权的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值