| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> JVM(Java Virtual Machine)(一)内存结构 -> 正文阅读 |
|
[Java知识库]JVM(Java Virtual Machine)(一)内存结构 |
? 目录 1.程序计数器(Program Counter Register)(寄存器) 4.4.1 jps工具:(java process statistic Java进程统计) ?4.4.4 jvisualvm可以查看对象个数,以及对象的详细信息 1.什么是JVM定义:?Java程序的运行环境(Java二进制字节码的运行环境也就是被编译过后的.class文件的运行环境) 好处:1.一次编写到处运行(只要安装了jdk) 2.自动内存管理,垃圾回收机制 3.数组下标越界检查 4.多态 关系:jvm、jre、jdk ? 2.学习JVM的作用1.理解底层的实现原理 2.向更高级的程序员看齐 3.常见的JVM由于JVM是一种规范,所以实现它的公司和团体有很多,我们较常用的还是(HotSpot,Oracle JDK edition?) 4.学习路线一、内存结构1.程序计数器(Program Counter Register)(寄存器)1.1 定义?JVM规范—程序计数器:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1? 当执行一条指令时,首先需要根据PC中存放的指令地址,将指令读取到指令寄存器中,称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。 1.2 作用?记住下一条jvm指令的执行地址。 过程:二进制字节码-->解释器-->机器码-->cpu 解释器从程序计数器中获取下一条jvm指令的执行地址。 1.3 特点1.是线程私有的,每个线程都有自己的程序计数器。 2.不会存在内存的溢出问题,仅仅存储指令的地址,有一定的大小限制 2.虚拟机栈(JVM Stacks)2.1 定义?JVM规范—虚拟机栈:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1 ?每个jvm都有一个私有的jvm栈,与线程同时创建。一个Jvm栈存储栈帧。jvm栈类似于传统的C语言的栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为jvm栈从来不直接操作,除了入栈和出栈,栈帧可能被分配。jvm堆栈的内存不需要是连续的。 在jvm规范第一版中,jvm栈被称为Java栈。 该规范允许jvm栈具有固定的大小,或者根据计算需要动态地扩展和收缩。如果jvm栈是固定大小的,则在创建栈时可以独立的选择每个Jvm的大小。 一个Jvm实现可以为程序员或用户提供对 Jvm栈初始大小的控制,以及在动态扩展或收缩 Jvm栈的情况下,对最大和最小大小的控制。 以下异常情况和jvm虚拟机栈相关联: ·如果一个线程中的计算需要一个比允许的更大的jvm栈,则jvm抛出一个StackOverflow Error。 ·如果可以动态扩展jvm栈,并且尝试了扩展,但可以提供的内存不足,无法实现扩展,或者,如果没有足够的内存可用于为新线程创建初始jvm栈,则jvm抛出Out of Memory Error。 2.2 作用2.3 特点?1.是线程私有的,每个线程都有自己的虚拟机栈。 2.每个栈由多个栈帧(Frame)组成,对应着每个方法调用时所占用的内存 3.每个线程只能有一个活动栈帧,对应着当前执行的那个方法 4.会出现内存溢出的情况. (1)栈内存过多导致内存溢出,比如递归调用 (2)栈帧过大导致栈内存溢出 2.4 问题辨析1.垃圾回收是否涉及栈内存? 栈是由多个栈帧组成,栈帧按照先进后出的执行策略,每一个栈帧执行完成会自动弹出虚拟机栈,从而释放内存,所以栈内存不需要垃圾回收。 2.栈内存分配越大越好吗? 虚拟机栈设置越大,相应的线程数会变小 https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html ? 3. 方法内的局部变量是否线程安全? 如果方法内的局部变量没有逃离方法的作用范围,它是线程安全的 如果局部变量引用了对象,或者逃离了方法的作用范围,需要考虑线程安全问题 3.本地方法栈(Native Method Stacks)3.1 定义?? JVM规范—本地方法栈:?https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1 ?jvm的实现可以使用常规的栈(俗称“C栈”)来支持方法(用Java编程语言以外的语言编写的方法)。本地方法栈也可以由jvm指令集的解释器的实现使用,例如C无法加载方法并且本身不依赖于常规栈的jvm实现不需要提供本地方法栈。如果提供,则在创建每个线程的时候,通常为每个线程分配本地方法栈。nativenative 此规范允许本地方法栈具有固定的大小,或者根据计算的需要动态扩展和收缩。如果本地方法栈的大小是固定的,则在创建该栈时,可以独立选择每个本地方法栈的大小。 jvm实现可以为程序员或者用户提供对本地方法栈初始大小的控制,以及在大小不同的本地方法栈的情况下,对最大和最小方法栈大小的控制。 以下异常情况和本地方法栈相关联: ·如果一个线程中的计算需要的本地方法栈大于允许的范围,则jvm抛出一个StackOverflow Error。 ·如果本地方法栈可以动态扩展,并且尝试了扩展,但可以提供的内存不足,无法实现扩展,或者,如果没有足够的内存可用于为新线程创建初始本地方法栈,则jvm抛出Out of Memory Error。 3.2 特点1.本地方法栈与虚拟机栈的区别是,虚拟机栈执行的的是Java方法,本地方法栈执行的是本地方法(Native Method),其他的基本上一致 2.线程私有的 3.会内存溢出 4.例如 Object中的clone() FileInputStream中的read() FileOutputStream中的write(int b) 4.堆(Heap)4.1 定义JVM规范—堆:? https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1 ?jvm具有一个在所有jvm线程之间共享的堆。堆是从中分配所有类实例和数组的内存的运行时数据区域。 堆创建于jvm启动时。对象的堆存储由自动存储管理系统(称为垃圾回收器)回收,从不显示解除分配对象。jvm假定没有特定类型的自动存储管理系统,存储管理技术可以根据实施者的系统要求进行选择。堆可以是固定的大小,也可以根据计算的需要进行扩展,如果不需要更大的堆。堆的内存不需要是连续的。 jvm实现可以为程序员或用户提供对堆的初始大小的控制,以及如果堆可以动态扩展或收缩,则可以控制最大和最小堆大小。 以下异常情况与堆相关联: ·如果计算需要的堆比自动存储管理系统可用的堆多,jvm将抛出一个OutOfMemoryError 4.2 作用及特点1.通过new关键字,创建对象都会使用堆内存 2.堆是线程共享的,堆中对象都需要考虑线程安全的问题 3.堆有垃圾回收机制 4.3 堆内存溢出以及如何调整堆内存的大小
? -Xmx8m可以调整堆内存的大小为8M ? ? ? ? 4.4 堆内存诊断
4.4.1 jps工具:(java process statistic Java进程统计)查看当前系统中有哪些java进程 ,右键进入Terminal可以直接进到路径下面 4.4.2 jmap工具(相当于给进程拍照片)查看堆内存占用情况,jmap - heap 进程id 查看堆内存使用变化 ps:前面的这些都是基本的堆内存的配置情况? 接下来我们看堆内存的使用情况: 下面这张图片是上述程序刚运行的时候堆内存的使用情况: new byte[]之后:? 将对象的引用置为null并且进行显示的gc之后:? ? ?可以明显地看到堆内存的变化情况: 4.4.3 jconsole工具(连续监测)?图形界面的,多功能的监测工具,可以连续监测,堆内存变化。 自动弹出: ? 选择你要监测的程序:链接的时候可能会提示不安全的链接,直接连接就行 ? ?可以清晰的看到内存的动态变化过程。 ?4.4.4 jvisualvm可以查看对象个数,以及对象的详细信息
我们首先依然使用jconsole查看一下内存使用情况,我们中间进行一下gc(右上角)发现内存使用减少的不明显,我就想知道到底是谁占用内存这么多,并且gc回收不掉。 ? ?也是会自动弹出来:选择要查看的程序,双击 点击抽样器,点击内存。 ?我们可以看到字节数组占用内存很大,我们点击右上角的堆Dump: ? 可以查找前多少个最大的对象: ? 双击还可以更加详细的查看细节: ? 5.方法区(Method Area)?5.1 定义jvm规范-方法区定义: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.1 jvm具有一个在所有jvm线程之间共享的方法区。方法区类似于常规语言的编译代码的存储区域,或者类似于操作系统进程中的“文本”段。它存储每个类的结构,如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口初始化中使用的特殊方法。 方法区是在jvm启动时创建的。尽管方法区在逻辑上是堆的一部分,但简单的实现可能会选择不进行垃圾回收或压缩它。此规范不要求方法区的位置或用于管理已编译代码的策略。方法区可以是固定大小的,也可以根据计算的需要进行扩展,如果不需要更大的方法区,则可以收缩。方法区的内存不需要是连续的。 jvm实现可以为程序员或用户提供对方法区的初始大小的控制,以及在方法区大小不同的情况下,对最大和最小方法区大小的控制。 以下异常情况与方法区相关联: ·如果方法区中的内存无法用于满足分配请求,jvm将抛出OutOfMemoryError。 5.2 特点1.是线程共享的 2.存在内存溢出的情况 5.3 组成1.jvm1.6 2.jvm1.8 (方法区被分配到本地内存) ?5.4 方法区内存溢出·1.8以前会导致永久代内存溢出(ps:这个就不做演示了) java.lang.OutOfMemoryError:PermGen space 调整大小:-XX:MaxPermSize=??? ·1.8之后会导致元空间内存溢出
?首先:最大元空间大小是很大的,所以先进行一下限制。其次,如果你不关闭压缩指针的话它会报:压缩类空间不足,这是因为在metaspace里面有一片空间专门存放压缩类文件。(网上说默认大小是1G)压缩指针默认是开启的。 ?关闭之后就可以看到元空间内存不足: 5.5 运行时常量池(区别于常量池)5.5.1 两者区别?常量池:就是一张表,虚拟指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息。 运行时常量池:常量池是*.class文件中的,当该类被加载时,它的常量池信息就会放入运行时常量池,并把里面的符号变为真实地址。 查看一下常量池:
找到编译后的代码:? ? 右键包名(是包名,不是类名): 执行javap??-v命令:?? ?看一下常量池: 还可以看一下main函数的底层执行过程:(具体的指令可以查看jvm指令手册) 5.6 StringTable
运行结果: ? ? ?? ? ? ? ? ?? ? ? ? ? ? ? ? ?? ?? ? ?? ? ? ??? ? ? ?? ???? ? |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 7:02:36- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |