初识JVM(JVM运行流程,JVM运行时数据区,内存布局中的异常)

简介: JVM(Java Virtual Machine),为Java虚拟机,虚拟机是指通过软件模拟一个具有完整的硬件功能并且运行在完全隔离的环境中的完整的计算机系统,JVM是一台被定制过的现实中不存在的计算机。

🚗一. JVM概述

JVM(Java Virtual Machine),为Java虚拟机,虚拟机是指通过软件模拟一个具有完整的硬件功能并且运行在完全隔离的环境中的完整的计算机系统,JVM是一台被定制过的现实中不存在的计算机


注意:选择题可能考


🚩HotSpot VM:


现在广泛使用的虚拟机,HotSpot指热点代码探测技术,它能通过计数器找到最具有编译价值的代码,触发即时编译(JIT),通过编译器与解释器协同工作,在最优化的程序响应时间与最佳执行性能中取得平衡值


对JIT即时编译的解释:热点代码比如一个while循环,每次循环边运行边翻译,效率低,JIT即时编译就将此热点代码直接编译为机器码,后面就不需要翻译可以直接执行,效率高


🚓二. JVM的运行流程

🚦一段Java代码是如何运行起来的呢?


通过java 类名会启动一个Java进程,系统为进程分配一块内存空间来执行进程的代码指令

有一条指令就会创建Java虚拟机

在Java虚拟机中会启动一个线程来执行main方法

Java虚拟机把class字节码的内容翻译为机器码,CPU来运行机器码


🏁整体看Java代码从编译到运行时的流程:

image.png

🚧说明:


Java程序在执行前先把Java代码转换为.class字节码,JVM先通过类加载器把字节码文件加载到Java进程内存的运行时数据区, 再将字节码翻译为底层系统指令所能识别的机器码,再交给CPU执行


🚕三. JVM运行时数据区(面试常考重点)

JVM运行时数据区也叫作内存布局,由堆区,方法区,虚拟机栈,本地方法栈,程序计数器这五部分组成


🚩jdk1.8把方法区称为元数据区,元数据区的常量池为运行时常量池

image.png


🛹1. 堆区(线程共享)

堆是最大的内存区域,程序运行时创建,程序退出时销毁,new创建对象都保存在堆中,字符串常量池也保存在堆中


堆中的新生代和老生代:新生代放新创建的对象,当经历了一定的GC次数之后还存活的对象就存放在老生代里


🛼2. 虚拟机栈(线程私有)

虚拟机栈的生命周期和线程相同,随着线程的创建而创建,线程的销毁而销毁,Java虚拟机栈描述的是Java方法执行的内存模型


每个方法都会创建一个栈帧用于存储局部变量表,操作数栈,动态链接,方法出口等信息,常说的栈内存就指的是虚拟机栈


🛸局部变量表:存放了编译器可知的基本数据类型,对象引用,方法参数,局部变量表所需的内存空间在编译期间就被分配好,进入一个方法,所需的局部变量表空间是确定的,在方法执行期间,不会改变局部变量表的大小

🛸操作数栈:每个方法都会生成一个先进后出的操作栈

🛸动态链接:指向运行时常量池的方法引用

🛸方法返回地址:PC寄存器的地址


结合代码示例理解栈和栈帧

public class Test {
    public static void swap(int m,int n){
        int temp = m;
        m = n;
        n = temp;
    }
    public static void main(String[] args) {
        int m = 10;
        int n = 20;
        swap(m,n);
        System.out.println("m:"+m+" "+"n:"+n);
    }
}

执行结果:m还是10,n还是20,没有发生交换

image.png

🚲3. 本地方法栈(线程私有)

Java虚拟机可能调用系统函数(本地方法),也可能调用native方法(本地方法),native方法底层使用c/c++写的,本地方法也需要一定的内存空间,本地方法栈就是用来保存这些本地方法的


🛵4. 程序计数器(线程私有)

程序计数器用来记录当前线程执行代码的行号


如果当前线程执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址

如果当前线程执行的是native方法,这个计数器的值为空


程序计数器是一块比较小的内存空间,🚩是唯一一个在JVM规范中没有规定任何OOM情况的区域


🏍️5. 方法区/元数据区(线程共享)

用来存储被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据


🚁jdk1.7,称为方法区,在Java进程的内存中

🚁jdk1.8,称为元空间,属于本地内存(不在Java进程内存中)


🚨运行时常量池:存放字面量与符号引用


🪂字面量:字符串(jdk1.8移动到堆中),final常量,基本数据类型的值

🪂符号引用:类和结构的完全限定名,字段的名称和描述符,方法的名称和描述符


🚙四. 内存布局中的异常

🛹1. 堆溢出

可以设置JVM参数-Xms:设置堆的最小值,-Xmx:设置堆的最大值

微信图片_20221029151836.jpg

设置参数为:-Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError

import java.util.ArrayList;
import java.util.List;
public class Test {
    static class OOMObject {
    }
    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while(true){
            list.add(new OOMObject());
        }
    }
}

运行上面代码观察堆溢出(堆OOM):OutOfMemoryError

微信图片_20221029152250.jpg

这里还需进一步分析是内存泄漏还是内存溢出


🚁内存泄漏:对象等数据不用但是也无法被GC,比如io资源未释放,资源的内存就无法被回收,就可能导致内存泄漏


🚁内存溢出:内存对象还存活,此时根据JVM堆参数与物理内存相比较检查是否应该把JVM堆内存调大,或检查对象的生命周期是否过长


🛼2. 栈溢出

如果线程请求的栈深度大于虚拟机所允许的最大深度,会抛出StackOverFlow异常


运行下面代码,观察栈溢出:StackOverflowError

public class Test {
    public static void method(){
        int a = 0;
        method();
    }
    public static void main(String[] args) {
        method();
    }
}

栈帧调用太深,一般在递归中出现,如递归没有返回值等等

微信图片_20221029152329.jpg

相关文章
|
7月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
735 55
|
5月前
|
缓存 固态存储 Windows
如何让内存发挥到最大效能?全面优化指南,提升电脑运行体验
电脑内存使用不合理会导致卡顿,本文教你如何优化内存性能。检查内存容量与主板支持上限,考虑升级或调整配置;关闭后台程序、管理浏览器标签、结束异常进程以释放内存;设置虚拟内存、调整视觉效果、定期重启提升效率;必要时增加内存条、选择高频内存、更换固态硬盘。避免盲目清理内存和依赖大内存忽视其他硬件瓶颈。只需合理设置,无需额外花钱,就能显著提升电脑速度。
|
8月前
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
724 6
|
4月前
|
编解码 Ubuntu Linux
ubuntu系统安装指南:免费且适合老旧电脑,4GB内存也能流畅运行!
点击启动台,找到并点击设置。在设置中,选择语言和区域,再点击管理语言。安装所需的语言包,输入密码进行确认。等待大约2分钟,语言包安装完成后,点击安装语言,选择中文选项。这里有简体和繁体两种选择,根据个人需求进行选择。再次等待2分钟,安装完成后,点击这里,选择中文并应用。然后,将出现的中文拖动到最上面,应用更改并退出设置。最后,重启虚拟机,再次进入系统时,你会发现界面已经变成了中文,而且系统依然保持流畅。Ubuntu系统不仅外观漂亮、干净,而且性能稳定、安全可靠。如果你的电脑内存只有4GB,或者你对Windows系统感到厌倦,那么Ubuntu绝对是一个值得尝试的选择。它不仅办公打印一应俱全,还拥
|
9月前
|
存储 缓存 算法
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
444 29
JVM简介—1.Java内存区域
|
9月前
|
缓存 监控 算法
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
|
7月前
|
存储 安全 Java
JVM深入原理(七)(一):运行时数据区
栈的介绍:Java虚拟机栈采用栈的数据结构来管理方法调用中的基本数据,先进后出,每一个方法的调用使用一个栈帧来保存栈的组成:栈:一个线程运行所需要的内存空间,一个栈由多个栈帧组成栈帧:一个方法运行所需要的内存空间活动栈帧:一个线程中只能有一个活动栈帧栈的生命周期:栈随着线程的创建而创建,而回收会在线程销毁时进行栈的执行流程:栈帧压入栈内执行方法执行完毕释放内存若方法间存在调用,那么会压入被调用方法入栈,执行完后释放内存,再执行当前方法,直到执行完毕,释放所有内存。
162 0
|
7月前
|
存储 缓存 安全
JVM深入原理(七)(二):运行时数据区
堆的作用:存放对象的内存空间,它是空间最大的一块内存区域.栈上的局部变量表中,可以存放堆上对象的引用。静态变量也可以存放堆对象的引用,通过静态变量就可以实现对象在线程之间共享。堆的特点:线程共享:堆中的对象都需要考虑线程安全的问题垃圾回收:堆有垃圾回收机制,不再引用的对象就会被回收方法区的概述:方法区是存放基础信息的位置,线程共享,主要包括:类的元信息:保存了所有类的基本信息运行时常量池:保存了字节码文件中的常量池内容静态常量池:字节码文件通过编号查表的方式找到常量。
104 0
|
10月前
|
存储 算法 Java
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
163 6
|
9月前
|
存储 Java C++
JVM 运行时数据区
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。这 些区域都有各自的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区 域则是依赖线程的启动和结束而建立和销毁。Java 虚拟机所管理的内存被划分为如下几个区域 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解 析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳 转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成; 为什么要线程计数器?因为线程是不具备记忆功能 Java 虚拟机

热门文章

最新文章