JVM笔记

img

Java代码执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smm9bR4f-1628844016582)(JVM.assets/image-20210805171335842.png)]

任何一个环节失败都不能正确生成字节码文件。

JVM的生命周期

  • 虚拟机的启动
    • 是通过引导类加载器创建一个初始类来完成的。
  • 虚拟机的执行
    • 程序开始就运行,程序结束就停止
    • 执行一个java程序时,实际上执行的是java虚拟机的进程
  • 虚拟机的退出
    • 程序正常执行结束
    • 遇到异常或者错误
    • 操作系统的错误
    • 调用Runtime类或者System类exit方法

手写一个JVM的需要类加载器和执行引擎

类加载器

java字节码文件起始的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-APaVDV21-1628844016584)(JVM.assets/image-20210805194224618.png)]

类加载的过程:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GMM7vVxd-1628844016589)(JVM.assets/image-20210805193039442.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aj9nRtx7-1628844016591)(JVM.assets/image-20210805193901572.png)]

类加载器的分类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9bsCaxHG-1628844016593)(JVM.assets/image-20210805203313401.png)]

  • 引导类加载器(Bootstrap Class Loader)
    • C/C++实现,嵌套在JVM内部
    • 加载核心类库
    • 出于安全考虑只加载Java、Javax、Sun等开头的类
  • 扩展类加载器(Extension Class Loader)
    • 派生于Class Loader类
  • 系统类加载器(App Class Loader)
    • 派生于Class Loader类
    • 负责加载环境变量classpath或系统属性
    • 该加载器时程序中默认的加载器,Java引用类都是由它完成
  • 自定义加载器(User-Defined Class Loader)
    • 直接或者间接继承了Bootstrap Class Loader
    • 扩展类加载器和系统类加载器都是自定义加载类
  • 不是继承关系,并且一般的类不能获取到引导类加载器
  • Java的核心类库都是使用引导类加载器加载的

类加载过程

  1. 加载阶段
    1. 通过一个类的全限定名获取此类二进制字节流
    2. 将这个字节流所代表静态存储结构转化为方法区的运行时数据结构
    3. 在内存中生成Class对象,作为方法区这个类的各种数据的访问入口
  2. 链接阶段
    1. 验证(Verify)
      • 确保Class文件的正确性
      • 四种验证(文件格式验证、元数据验证、字节码验证、符号引用验证)
    2. 准备(Prepare)
      • 分配内存、赋初始值(零值或者null)
      • 不包含final修饰的static,因为final在编译时就分配了值(显式初始化)
    3. 解析(Resolve)
      • 将常量池中的符号引用转化为直接引用的过程
  3. 初始化阶段
    • 初始化阶段就是执行类构造器方法<clinit>()的过程
    • 此方法不需要定义,自动收集类中所有类变量的赋值动作和静态代码块中的语句
    • 任何一个类声明以后,内部的至少有一个构造器<init>()

双亲委派机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohifaCGu-1628844016594)(JVM.assets/image-20210805210156482.png)]

  1. 类加载器收到类加载请求,它并不会自己区加载,而是把这个请求委托给父类加载器去执行
  2. 如果父类加载器还有父类,继续委托达到引导类加载器
  3. 随后,若当前加载器能加载完成则返回,若不能,则让子类加载器去完成。

**沙箱安全机制:**不能在java.lang包自定义类,或者重写其他类

运行时数据区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-81hrEMNe-1628844016594)(JVM.assets/image-20210806092834925.png)]

PC寄存器

存储运行的下一条指令

问:使用PC寄存器字节码指令地址有什么用?

答:因为CPU需要不停的切换线程,切换回来的时候就知道接着从哪里继续执行

问:为什么使用PC寄存器记录当前线程的执行地址?

答:JVM的字节码编译器就需要通过改变PC寄存器的值来明确下一条字节码指令

JVM栈

栈帧包含(局部变量表,操作数栈,动态链接,方法返回地址,附加信息)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aPYqbw2B-1628844016596)(JVM.assets/image-20210806102046692.png)]

局部变量表(数字数组):方法参数,局部变量,数据基本类型,对象引用。

操作数栈(主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间)

动态链接(链接到本地方法栈)

栈是不存在垃圾回收的问题,但存在OOM(内存溢出)

-Xss 1024k(设置栈的大小)

问:举例栈溢出的情况?

答:StackOverflowError、OOM

问:调整栈大小,就能保证不出现溢出吗?

答:不能,如果使用递归没有终止的情况

问:分配的栈内存越大越好吗?

答:不是,挤占别的空间

问:垃圾回收会涉及到栈吗?

答:不会,因为只有进栈和出栈,不存在垃圾

问:方法中定义的局部变量是否线程安全?

答:具体问题具体分析(对象内部产生内部消亡那个的是安全的,否则不是)

本地方法栈

与JVM栈发挥的作用相似,区别:虚拟机栈为虚拟机执行java方法服务,而本地方法栈使用的是Native方法服务。

  1. 本地方法栈就是管理本地方法的
  2. 本地方法是使用C语言实现的
  3. 与本地方法库打交道

  • 所有的对象实例以及数组都应当运行时分配在堆上
  • 数组和对象永远不会存储在栈上,因为栈帧中保存引用,这个引用指向对象或者数组在堆中的位置
  • 方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集的时候才会被移除
  • 堆时GC执行垃圾回收的重点区域
  • -Xms(起始内存)【年轻代和老年代】
  • -Xmx(最大内存)
内存细分
  • java7之前:新生区+养老区+永久区(方法区)
  • java8之后:新生区+养老区+元空间
  • 新生区=伊甸园区+s0+s1(比例8:1:1)
  • 1/3新生代,2/3老年区
  • 当伊甸园区满了触发MinorGC
  • 当达到阈值15的时候,晋升(Promotion)到老年代
  • 大对象直接进入老年代

MinorGC、MajorGC、FullGC

  • MinorGC:只是新生代的垃圾回收
    • 只有伊甸园区满了才会触发,幸存区满不会
  • MajorGC:只是老年代的垃圾回收
    • 执行之前至少执行一次MinorGC
    • 目前只有CMS GC会有单独收集老年代的行为
  • Mixd GC:收集整个新生代以及部分老年代的垃圾回收
    • 目前,只有G1 GC会有这种行为
  • Full GC:收集整个java堆和方法区的垃圾收集

方法区(原空间)

  • 独立于堆的内存空间
  • 方法区的大小决定了系统可以保存多少个类
    • 加载大量的第三方jar包
    • 部署工程过多
    • 大量动态生成的反射类
    • 以上都会造成方法区溢出
  • 类型信息、运行时常量池、静态变量、即时编译后的代码缓存
    • 运行时常量池
      • 是方法区的一部分
      • 常量池表存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中
      • 具备动态性
  • 回收
    • 只要常量池中的常量没有被任何地方引用,就可以被回收
    • 判断类是否可以被回收
      • 该类的所有实例被回收
      • 加载该类的加载器被回收(很难达成)
      • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

执行引擎

java是半编译半解释型语言

  • 解释器(解析执行)
    • 逐行执行翻译成机器指令,效率低下,但响应速度快
    • 字节码解释器、模板解释器(与模板函数相关联)
  • JIT编译器(编译执行)
    • 字节码编译程机器指令(翻译成机器指令耗时)
    • 将热点代码缓存
    • 栈上替换
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAwnMf6h-1628844016597)(JVM.assets/image-20210807103553597.png)]
    • 热点代码缓存在元空间,在jdk8以后元空间使用的是本地内存,故本地内存也可以
    • 热度衰减:超过一定时间限度,这个方法的调用计数器就会被减少一半

本地方法库

  • 与java环境外的交互
  • 与操作系统交互
  • Sun’s Java
  • native关键字

对象实例化

  • 创建对象的方式
    • new
    • Class的newInstance():jdk8能用,jdk9过时(使用起来苛刻,只能调用无参构造,权限必须是public)
    • Constructor的newInstance(XXX):反射,可以调用无参构造和有参构造,权限没有要求
    • 使用clone():不调用任何构造器,当前类需要实现Cloneable接口,实现clone方法
    • 使用反序列化:从文件或者网络中获取对象的二进制流
    • 第三方库Objenesis
  • 创建对象的步骤
    1. 判断对象对应的类是否被加载、链接、初始化
    2. 为对象分配内存
    3. 处理并发安全问题
    4. 初始化分配到的空间
    5. 设置对象头
    6. 执行init方法进行初始化

四大垃圾回收算法

标记阶段
  1. 引用计数算法
    • 有引用计数器就+1,引用失效计数器就-1,只要计数器为0就回收
    • 没法处理循环引用的情况,导致java的垃圾回收器没用使用这一算法
  2. 可达性分析算法
    • 以根对象(GC Roots)集合为起始点,从上之下搜索对象是否可达,不可达的就是垃圾
    • GC Roots:
      • 虚拟机栈中引用的对象
      • 本地方法栈内引用的对象
      • 方法区中类静态属性引用的对象
      • 方法区中常量引用的对象
    • 解决了循环引用的问题
清除阶段
  1. 标记-清除算法(Mark-Sweep)
    • 停止整个程序(STW stop the world),需要停顿,所以体验不好,效率也不高
    • 标记:从根节点出发,标记到非垃圾对象
    • 清除:对堆内存从头到尾进行遍历,如果发现某个对象在其Header中没有被标记,将其回收
  2. 复制算法(Copying)
    • 准备两块相同的空间AB,A存数据,清除的时候把有用的复制到B,随后清除A,然后交换
    • 运行高效,没有碎片
    • 但是需要两倍的内存空间,开销大
    • 适用于年轻代的垃圾回收
  3. 标记-压缩算法(Mark-Compact)
    • 从根节点出发,标记可用对象
    • 将存活对象压缩到内存的一段,按顺序存放(连续存储)
    • 清除其余空间的所有无用对象
    • 适用于老年代的垃圾回收
    • 效率比较低
  4. 分代收集算法
    • 新生代采用复制算法
    • 老年代采用标记-清除和标记-压缩算法

七大垃圾回收器

  1. Serial单线程垃圾回收器
    • 要停止所有工作线程
    • 默认新生代收集器
  2. ParNew垃圾收集器
    • 是Serial的多线程版
    • 新生代
  3. Parallel Scavenge并行垃圾回收器
    • 新生代收集器
    • 使用的复制算法
    • 多线程
  4. Serial Old垃圾回收器
    • 老年代收集器
    • 单线程
    • 标记-压缩算法
  5. Parallel Old垃圾回收器
    • 老年代收集器
    • 多线程
    • 标记-压缩算法
  6. CMS垃圾回收器
    • 标记-清除算法
    • 并发收集、低停顿
  7. G1垃圾收集器
    • 标记-压缩算法
    • 精确的控制停顿,明确指定一个时间段内执行
      rial的多线程版
    • 新生代
  8. Parallel Scavenge并行垃圾回收器
    • 新生代收集器
    • 使用的复制算法
    • 多线程
  9. Serial Old垃圾回收器
    • 老年代收集器
    • 单线程
    • 标记-压缩算法
  10. Parallel Old垃圾回收器
    • 老年代收集器
    • 多线程
    • 标记-压缩算法
  11. CMS垃圾回收器
    • 标记-清除算法
    • 并发收集、低停顿
  12. G1垃圾收集器
    • 标记-压缩算法
    • 精确的控制停顿,明确指定一个时间段内执行

热门文章

暂无图片
编程学习 ·

Java输出数组的内容

Java输出数组的内容_一万个小时-CSDN博客_java打印数组内容1. 输出内容最常见的方式// List<String>类型的列表List<String> list new ArrayList<String>();list.add("First");list.add("Second");list.add("Third");list.ad…
暂无图片
编程学习 ·

母螳螂的“魅惑之术”

在它们对大蝗虫发起进攻的时候&#xff0c;我认认真真地观察了一次&#xff0c;因为它们突然像触电一样浑身痉挛起来&#xff0c;警觉地面对限前这个大家伙&#xff0c;然后放下自己优雅的身段和祈祷的双手&#xff0c;摆出了一个可怕的姿势。我被眼前的一幕吓到了&#xff0c;…
暂无图片
编程学习 ·

疯狂填词 mad_libs 第9章9.9.2

#win7 python3.7.0 import os,reos.chdir(d:\documents\program_language) file1open(.\疯狂填词_d9z9d2_r.txt) file2open(.\疯狂填词_d9z9d2_w.txt,w) words[ADJECTIVE,NOUN,VERB,NOUN] str1file1.read()#方法1 for word in words :word_replaceinput(fEnter a {word} :)str1…
暂无图片
编程学习 ·

HBASE 高可用

为了保证HBASE是高可用的,所依赖的HDFS和zookeeper也要是高可用的. 通过参数hbase.rootdir指定了连接到Hadoop的地址,mycluster表示为Hadoop的集群. HBASE本身的高可用很简单,只要在一个健康的集群其他节点通过命令 hbase-daemon.sh start master启动一个Hmaster进程,这个Hmast…
暂无图片
编程学习 ·

js事件操作语法

一、事件的绑定语法 语法形式1 事件监听 标签对象.addEventListener(click,function(){}); 语法形式2 on语法绑定 标签对象.onclick function(){} on语法是通过 等于赋值绑定的事件处理函数 , 等于赋值本质上执行的是覆盖赋值,后赋值的数据会覆盖之前存储的数据,也就是on…
暂无图片
编程学习 ·

Photoshop插件--晕影动态--选区--脚本开发--PS插件

文章目录1.插件界面2.关键代码2.1 选区2.2 动态晕影3.作者寄语PS是一款栅格图像编辑软件&#xff0c;具有许多强大的功能&#xff0c;本文演示如何通过脚本实现晕影动态和选区相关功能&#xff0c;展示从互联网收集而来的一个小插件&#xff0c;供大家学习交流&#xff0c;请勿…
暂无图片
编程学习 ·

vs LNK1104 无法打开文件“xxx.obj”

写在前面&#xff1a; 向大家推荐两本新书&#xff0c;《深度学习计算机视觉实战》和《学习OpenCV4&#xff1a;基于Python的算法实战》。 《深度学习计算机视觉实战》讲了计算机视觉理论基础&#xff0c;讲了案例项目&#xff0c;讲了模型部署&#xff0c;这些项目学会之后可以…
暂无图片
编程学习 ·

工业元宇宙的定义与实施路线图

工业元宇宙的定义与实施路线图 李正海 1 工业元宇宙 给大家做一个关于工业元宇宙的定义。对于工业&#xff0c;从设计的角度来讲&#xff0c;现在的设计人员已经做到了普遍的三维设计&#xff0c;但是进入元宇宙时代&#xff0c;就不仅仅只是三维设计了&#xff0c;我们的目…
暂无图片
编程学习 ·

【leectode 2022.1.15】完成一半题目

有 N 位扣友参加了微软与力扣举办了「以扣会友」线下活动。主办方提供了 2*N 道题目&#xff0c;整型数组 questions 中每个数字对应了每道题目所涉及的知识点类型。 若每位扣友选择不同的一题&#xff0c;请返回被选的 N 道题目至少包含多少种知识点类型。 示例 1&#xff1a…
暂无图片
编程学习 ·

js 面试题总结

一、js原型与原型链 1. prototype 每个函数都有一个prototype属性&#xff0c;被称为显示原型 2._ _proto_ _ 每个实例对象都会有_ _proto_ _属性,其被称为隐式原型 每一个实例对象的隐式原型_ _proto_ _属性指向自身构造函数的显式原型prototype 3. constructor 每个prot…
暂无图片
编程学习 ·

java练习代码

打印自定义行数的空心菱形练习代码如下 import java.util.Scanner; public class daYinLengXing{public static void main(String[] args) {System.out.println("请输入行数");Scanner myScanner new Scanner(System.in);int g myScanner.nextInt();int num g%2;//…
暂无图片
编程学习 ·

RocketMQ-什么是死信队列?怎么解决

目录 什么是死信队列 死信队列的特征 死信消息的处理 什么是死信队列 当一条消息初次消费失败&#xff0c;消息队列会自动进行消费重试&#xff1b;达到最大重试次数后&#xff0c;若消费依然失败&#xff0c;则表明消费者在正常情况下无法正确地消费该消息&#xff0c;此时…
暂无图片
编程学习 ·

项目 cg day04

第4章 lua、Canal实现广告缓存 学习目标 Lua介绍 Lua语法 输出、变量定义、数据类型、流程控制(if..)、循环操作、函数、表(数组)、模块OpenResty介绍(理解配置) 封装了Nginx&#xff0c;并且提供了Lua扩展&#xff0c;大大提升了Nginx对并发处理的能&#xff0c;10K-1000K Lu…
暂无图片
编程学习 ·

输出三角形

#include <stdio.h> int main() { int i,j; for(i0;i<5;i) { for(j0;j<i;j) { printf("*"); } printf("\n"); } }
暂无图片
编程学习 ·

stm32的BOOTLOADER学习1

序言 最近计划学习stm32的BOOTLOADER学习,把学习过程记录下来 因为现在网上STM32C8T6还是比较贵的,根据我的需求flash空间小一些也可以,所以我决定使用stm32c6t6.这个芯片的空间是32kb的。 #熟悉芯片内部的空间地址 1、flash ROM&#xff1a; 大小32KB&#xff0c;范围&#xf…
暂无图片
编程学习 ·

通过awk和shell来限制IP多次访问之学不会你打死我

学不会你打死我 今天我们用shell脚本&#xff0c;awk工具来分析日志来判断是否存在扫描器来进行破解网站密码——限制访问次数过多的IP地址&#xff0c;通过Iptables来进行限制。代码在末尾 首先我们要先查看日志的格式&#xff0c;分析出我们需要筛选的内容&#xff0c;日志…
暂无图片
编程学习 ·

Python - 如何像程序员一样思考

在为计算机编写程序之前&#xff0c;您必须学会如何像程序员一样思考。学习像程序员一样思考对任何学生都很有价值。以下步骤可帮助任何人学习编码并了解计算机科学的价值——即使他们不打算成为计算机科学家。 顾名思义&#xff0c;Python经常被想要学习编程的人用作第一语言…
暂无图片
编程学习 ·

蓝桥杯python-数字三角形

问题描述 虽然我前后用了三种做法&#xff0c;但是我发现只有“优化思路_1”可以通过蓝桥杯官网中的测评&#xff0c;但是如果用c/c的话&#xff0c;每个都通得过&#xff0c;足以可见python的效率之低&#xff08;但耐不住人家好用啊&#xff08;哭笑&#xff09;&#xff09…