-
Java JVM相关
1,基础知识
- JVM运行流程
- Java源文件—->编译器(工具)—->字节码文件
- 字节码文件—->JVM(工具)—->机器码
- Java源文件—->字节码文件—->加载配置(根据系统版本,寻找jvm.cfg文件)—->根据配置文件找到jvm.dll—->初始化jvm,获取JNI接口—->找到main方法并执行
- 通过jvm.cfg文件找到对应的jvm.dll ,jvm.dll则是java虚拟机的主要实现。接下来会初始化JVM,并且获取JNI接口,什么是JNI接口,就是java本地接口。通过JNI接口(它还常用于java与操作系统、硬件交互),找到class文件后并装载进JVM,然后找到main方法,最后执行
- jvm基本结构
- JVM之内存空间
- 方法区
- 简单的说:方法区是各个线程共享的区域,存放类信息、常量、静态变量。
- 细得说:静态变量+常量+类信息+运行时常量池存在方法区中,实例变量存在堆内存中。
- java堆
- java堆也是线程共享的区域。
- 堆这块区域是JVM中最大的,应用的对象和数据都是存在这个区域,这块区域也是线程共享的,也是 gc 主要的回收区,一个 JVM 实例只存在一个堆内存,堆内存的大小是可以调节的。
- 堆内存概述
- 新生区:新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。
- 伊甸区(Eden space):所有的类都是在伊甸区被new出来的
- 幸存者区(Survivor pace)
- 0区(Survivor 0 space)
- 1区(Survivor 1 space)
- 当伊甸园的空间用完时,程序又需要创建对象,JVM的垃圾回收器将对伊甸园进行垃圾回收**(Minor GC)**,将伊甸园中的剩余对象移动到幸存0区。
- 幸存0区也满了,再对该区进行垃圾回收,然后移动到1区。
- 那如果1去也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生Major GC(FullGCC),进行养老区的内存清理。若养老区执行Full GC 之后发现依然无法进行对象的保存,就会产生OOM异常“OutOfMemoryError”。
- 养老区:养老区用于保存从新生区筛选出来的 JAVA 对象,一般池对象都在这个区域活跃。
- 永久区:永久存储区是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。
- java栈
- 每个线程私有的区域,它的生命周期与线程相同,一个线程对应一个java栈,每执行一个方法就会往栈中压入一个元素,这个元素叫“栈帧”,而栈帧中包括了方法中的局部变量、用于存放中间状态值的操作栈。
- 如果java栈空间不足了,程序会抛出StackOverflowError异常,想一想什么情况下会容易产生这个错误,对,递归,递归如果深度很深,就会执行大量的方法,方法越多java栈的占用空间越大。
- 本地方法栈:本地方法栈角色和java栈类似,只不过它是用来表示执行本地方法的,本地方法栈存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统、硬件交互的目的。
- 堆内存和栈内存说明
- 基础数据类型直接在栈空间分配,方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。
- 引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 。方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收。局部变量new出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。
- 数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小。
- 垃圾收集器
- Serial收集器:Serial收集器是最基本、发展历史最悠久的收集器。这个收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作, 更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
- ParNew收集器
- Parallel Scavenge收集器:Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。
- Serial Old收集器:Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用“标记-整 理”算法。
- Parallel Old收集器:Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
- CMS收集器:CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前Java应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
- G1收集器
- PC寄存器:
- 概述:JVM中的程序计数寄存器(Program Counter Register),Register的命名源于CPU的寄存器,寄存器存储指令相关的现场信息。CPU只有把数据装载到寄存器才能够运行。这里,并非是广义上所指的物理寄存器,或许将其翻译为PC计数器(或指令计数器)会更加贴切(也称为程序钩子),并且也不容易引起一些不必要的误会。JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟。
- 简单介绍
- 是一块很小的内存空间,几乎可以忽略不计,也是运行速度最快的存储区域。
- 在JVM规范中,每个线程都有它自己的PC寄存器,是线程私有的,生命周期与线程的生命周期保持一致。
- 任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法,PC寄存器会存储当前线程的正在执行的Java方法的JVM指令地址;或者,如果是执行的native方法,则是未指定值。
- PC寄存器是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个寄存器来完成。
- 字节码解释器工作时就是通过改变这个寄存器的值来选取下一条需要执行的字节码指令。
- PC寄存器是唯一 一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
- 方法区(元数据区)和堆区是有GC(垃圾回收)的,而栈区和PC寄存器是没有的;栈区、方法区、堆区是有OOM(OutOfMemoryError)的,而PC寄存器没有。
- JVM中的PC寄存器是对物理PC寄存器的一种抽象模拟。
- 使用PC寄存器存储字节码指令地址有什么用呢?(为什么使用PC寄存器记录当前线程的执行地址呢?)
- 因为CPU需要不停的切换各个线程,这时候切换回来后,就得知道是从哪个指令开始继续执行。JVM的字节码解释器就需要通过改变PC寄存器的值来明确下一条应该执行什么样的字节码按指令。
- 本地方法接口
- 一个Native Method 就是一个Java调用非 java 代码的接口。
- 一个Native Method 是这样一个java方法:该方法的底层实现由非java语言来实现的。比如是C/C++语言。
- 它的主要作用是融合不同的编译语言为java所用
- 执行引擎
- 执行引擎概述
- 物理机的执行引擎是直接建立在处理器、缓存、指令集合操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,能够执行那些不被硬件直接支持的指令集格式
- 执行引擎的任务是将字节码指令解释编译为对应平台上的本地机器指令来让一个Java程序运行起来,使之在操作系统上直接运行
- 执行引擎的工作过程
- 执行引擎在执行什么样的字节码指令完全依赖PC寄存器
- 每执行完一项指令操作后,PC寄存器机会更新下一条需要被执行的指令地址
- 方法在执行的过程中,执行引擎可能会通过储存在局部变量表中的对象引用准确定位到储存在Java堆区中的对象实例信息以及通过对象头中的元数据指针定位到目标对象的类型信息
- Java源码编译机制
- 代码编译由JAVA源码编译器来完成。主要是将源码编译成字节码文件(class文件);字节码文件格式主要分为两部分:常量池和方法字节码。
- Java源码编译机制由以下三个过程组成:
- 分析和输入到符号表
- 注解处理
- 语义分析和生成class文件
- 类加载机制
- 类执行机制
-
相关阅读:
rust 基础数据类型
深入理解LTE网络的CDRX
tf.queue
Java Netty - Buffer类
【C++ 学习 ㉖】- 布隆过滤器详解(哈希扩展)
Mybatis
AJAX & Axios & JSON (外加JSON数据格式案例)
知识增强的大语言模型
GPIO定义
设计模式-观察者模式
-
原文地址:https://blog.csdn.net/hanlin_zhao/article/details/127984625