Java虚拟机学习笔记 第一章第一部分

Java虚拟机学习笔记 第一章第一部分,第1张

Java虚拟机学习笔记 第一章第一部分 Java虚拟机学习笔记–第一章第一部分 1 Java内存区域与内存溢出异常 1.1运行时的数据区域

​ java运行时的内存包含以下几个区域

​ 1.程序计数器

​ 2.Java虚拟机栈

​ 3.本地方法

​ 4.Java堆

​ 5.方法区

1.1.1 程序计数器

​ 程序计数器根据书中所言,就是一个记录程序运行到第几行的区域,所占内存比较小,属于线程私有,即一个线程一个程序计数器。

​ 对于Java方法,程序计数器记录的是正在执行的字节码地址而native方法则是未定义。

1.Java线程执行native方法时程序计数器为空(未定义),如何确保native执行完后的程序执行的位置

​ 这里的native方法并不是用java写的,不用去理会JVM的程序计数器(pc register)的概念,因此Java的程序计数器会出现未定义的情况,而native是由本地平台执行的,比如用C语言写的,在线程切换的时候就会根据C语言的切换规则切换回去,它在执行结束后会返回下一条指令的位置,不必担心Java找不到下一条指令。

2.课外小知识Native方法

​ native方法简单来说是在Java中需要使用Java不能提供的一些功能,例如直接控制 *** 作系统的方法,因此,它也就没有很好的可移植性,对于native方法,它类似抽象方法,不进行实现,通过非java语言进行实现。

​ 在java文件中,声明native方法, loadLibrary() 加载,通过自己写一个.cpp文件实现native方法,再编译成dll,由之前的loadLibrary()进行加载。

​ 当一个带有本地方法的类被加载时,其相关的DLL并未被加载,因此指向方法实现的指针并不会被设置。当本地方法被调用之前,这些DLL才会被加载,这是通过调用java.system.loadLibrary()实现的。 //本段落转载自 (67条消息) Java的native方法_wike的专栏-CSDN博客_java native方法

1.1.2虚拟机栈

​ 虚拟机栈中存储的是Java方法的内存模型,每一个Java方法会生成一个栈帧(stack frame) 然后存储进入虚拟机栈中。

​ 栈帧中存储局部变量表, *** 作数栈,动态链接,方法返回地址,一些额外的附加信息。

局部变量表

​ 局部变量表用于存储各种数据类型,最小单位是槽(slot,32位),包括 boolean、byte、char、short、int、float、reference和 returnAddress ,long和double需要两个槽。

局部变量表有一些特点。

1.如果是非static方法,那么局部变量表的第0位是方法所属对象的引用.

2.Slot可以复用,在超出变量作用域的时候,gc会进行回收,给别的变量使用。

3.jvm不会给局部变量赋初始值,只给全局变量赋初始值。

*** 作数栈

​ *** 作数栈存储的也可以是一些数组,通常在这里进行对数据的计算, *** 作数栈是通过后进先出实现的而局部变量表是通过索引的,在它会将变量压入栈,计算,最后d栈,存储进入局部变量表。附 *** 作数栈实践 (67条消息) Java虚拟机站之 *** 作数栈_Lisam Blog-CSDN博客_ *** 作数栈

动态链接与静态解析

​ 对于方法的引用,java在编译的时候都是符号引用,因此,对于可知的方法调用,采取的是静态解析,也就是直接引用,而动态链接的作用,是将不可知的方法调用,在运行期间转换成直接引用。

(67条消息) JVM-虚拟机栈之动态链接_FloatDreamed的博客-CSDN博客_虚拟机栈动态链接

1.1.3 本地方法栈

​ 同Java虚拟机栈

​ 当线程调用 Java 方法时,虚拟机会创建一个栈帧并压入 Java 虚拟机栈。然而当它调用的是 native 方法时,虚拟机会保持 Java 虚拟机栈不变,也不会向 Java 虚拟机栈中压入新的栈帧,虚拟机只是简单地动态连接并直接调用指定的 native 方法。(因为之前你已经导入过该native方法的实现了,在这里直接调用即可)

引自 JVM 系列 - 内存区域 - 本地方法栈(四) - 简书 (jianshu.com)

1.1.4 Java堆

​ Java堆用于存储对象实例,在虚拟机被创建时就存在。被所有线程共享,Java堆的内存逻辑上连续,物理上可以不连续,可扩展。

1.1.5 方法区

​ 同Java堆,线程共享,但是它存储的是已被虚拟机加载的类的信息,常量(常量池),静态变量,代码等。

对于方法区,HotSpot存在永久代问题

​ 即曾经尝试使用堆的垃圾回收应用在方法区中,但目前已经放弃,因为存在内存泄漏的问题。

​ 但是对于方法区,其实并不需要垃圾回收,但不意味着数据的永久保存,对常量池的回收以及类的卸载依然存在垃圾回收。

1.1.6 运行时常量池 字面量

​ 对值的表示,这里的值指的是正数,浮点数,布尔类型,字符类型等。

符号引用

​ 对不确定地址的东西用一串符号来表示,符号是字面量。

​ 运行时常量池常常存储,编译器生成的各种字面量和符号引用。直接引用(指针等)也可以存储在常量池 中,运行时常量池具有一个特性:动态性。在运行期间也可以将新的常量放入常量池当中。常见使用: String.intern() //这是一个native方法 intern的本质是改变引用的方向。

​ 关于intern()方法的详解可看 Java intern() 方法 | 菜鸟教程 (runoob.com)

1.1.7 直接内存

​ 直接内存并不存在与Java虚拟机中,而是存在本地当中,利用Native函数进行分配内存,不受Java虚拟机的限制,知识在Java堆中有一个DirectByteBuffer对象对该内存进行引用,直接内存受本机总内存以及处理器寻址空间的影响。如果忽略直接内存,那么在虚拟机内存分配时你以为内存并没有超过限制,但是在进行内存扩展时就会出现OutOfMemoryError的异常。

er对象对该内存进行引用,直接内存受本机总内存以及处理器寻址空间的影响。如果忽略直接内存,那么在虚拟机内存分配时你以为内存并没有超过限制,但是在进行内存扩展时就会出现OutOfMemoryError的异常。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/zaji/5720229.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存