JVM(一)常见知识点及概述

思维导图


在这里插入图片描述




一、常见知识点

1.用户线程与内存线程:

1.1 多对一:不需要切换,线程创建、调度、同步非常快;但是如果其中一个用户线程阻塞会造成其他线程无法执行,且无法像内核线程一样实现较完整的调度、优先级;
1.2 一对一:java的jvm几乎把所有对线程的操作都交给了系统内核操作,线程真正启动顺序不一定是按我们启动的顺序,会引起用户态和内核态的频繁切换;如果系统出现大量线程,回家降低系统性能。

2.运行时数据区:

在这里插入图片描述

3.内存回收:

在这里插入图片描述

4.内存溢出:

1.1 栈溢出


1.2 堆溢出
在这里插入图片描述
》第8行设置会在堆溢出会导出Damping日志

1.3 方法区溢出
1.4 本机直接内存溢出

5.内存泄漏:

1.1 不使用的内存,却没有被释放;
1.2 每一次请求进来或者每一次操作处理都分配了内存,却有部分不能回收(或未释放),随着请求越来越多,内存泄漏就会越来越严重,必然造成内存溢出。
1.3 内存泄漏一般是资源管理问题或者程序bug,内存溢出则是内存空间不足和内存泄漏的最终结果。

6.hotspot对象头包含哪些部分:

在这里插入图片描述

7.根据类分析对象的内存占用:

在这里插入图片描述

8.jvm启动参数:

高效记忆:jvm配置参数

(1)这个星期天上午,衣物堆内存(堆内存)在很多需要使用算法机洗(GC算法)的衣服,而且因为衣服太多了,所以需要几台洗衣机并行机洗(GC并行线程数)。
(2)中午终于洗完衣服了衣服,觉得很有成就感,于是我写下了巨大的日志(GC日志)并保存在日志文件(GC日志文件)夹中。
(3)但是日志文件超过了原数据区域的最大值(元数据区的最大值),于是我压缩了单个日志形成文件占用大小(单个线程栈的大小),并设置之后如果内存溢出自动转存(堆内存溢出自动进行dump)云端。

在这里插入图片描述

8.G1垃圾收集器特点:

1.空间整合:哪块垃圾最多优先清理
在这里插入图片描述
2.多线程+并发+可预测停顿
在这里插入图片描述

9.排查OOM的方法:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10.jvm的相关命令工具:

高效记忆:jvm命令

(1)先用jps列出进程,再用jstat打印状态,然后再使用jinfo查看信息,
(2)其次再用jmap堆转存快照,以及用jstack转存当前线程快照,最后用jhat查看堆内存快照。
(3)实战cpu飙升:
a.先用top后用shift+p找到占用CPU最高的进程,再用top -p 进程号后用H找到占用cpu最高的线程,
b.再执行jstack 线程号输出线程信息,同时根据线程号转成的16进制找到对应的堆信息,然后再找到对应的代码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.java8默认垃圾收集器:

在这里插入图片描述

12.并行垃圾收集器:

在这里插入图片描述

13.swt:

在这里插入图片描述
安全点:方法调用、循环跳转、异常跳转;设置标志位,并不断轮询,主动停止。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

14.cpu使用率飙升,怎么排查?

先通过top命令找到cpu使用率高的线程;top -p 进程号;该界面输入H查找最高cpu的线程;执行jstack 进程号做dump输出线程信息; 同时根据线程的16进制找到对应的堆信息,然后再找出对应的代码
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
6、最后根据线程信息定位到具体代码

15.垃圾回收器的三色标记:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

16.类加载、类加载器:

在这里插入图片描述
在这里插入图片描述

17.JVM简介及原理

17.1 简介

17.1.1 Java SE、JDK、JRE、JVM
  • Java SE:Java平台标准版,包含JDK
  • JDK:包含JRE,和编译器、调试器等命令行开发工具,可以用来开发Java应用程序 。
  • JRE:包含JVM,和运行以Java编程语言编写的applet和应用程序所必需的库,和其他组件。
  • JVM:即Java虚拟机
17.1.2 虚拟机

执行一系列虚拟命令的虚拟的机器

包含:

  • 系统虚拟机:

    • 完全对物理计算机的仿真,几乎和真实的PC操作系统一样。
    • 如常用的 Vmare 以及 Visual Box 软件,通过这些软件可以模拟出完整计算机系统,具有完整硬件系统功能,运行在一个完全隔环境中。
  • 程序虚拟机:

    • 专门为执行单个计算程序而产生。
    • 最典型的就是Java虚拟机,在Java虚拟机中执行字节码文件命令。
17.1.3 Java虚拟机特点
  • 语言无关:只要编写程序的语言能够编译成class文件,就能在Java虚拟机运行

在这里插入图片描述


  • 平台无关
  • 一次编写,到处运行。
  • 不同的计算机系统安装对应不同的Java虚拟机,Java虚拟机运行编译好的class文件。

在这里插入图片描述


17.2 原理

  • Java虚拟机,在实际的计算机上仿真模拟各种计算机功能。
  • Java虚拟机基于计算机下层的操作系统和硬件平台,利用软件方法实现的抽象计算机。
  • Java虚拟机有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。
  • 源文件(如.java文件)经编译器(如javac编译器)编译成字节码程序(.class文件),平台通过Java虚拟机将字节码程序(其中的每一条指令)翻译成对应平台的机器码,最后平台执行机器码运行程序。

在这里插入图片描述


17.3 总结

以Java源代码为例:

  • Java .java源代码文件,经过JDK的编译器编译成.class字节码程序
  • 平台(如计算机系统,下同省略不写)安装对应平台的Java虚拟机
  • .class字节码程序通过安装好的Java虚拟机翻译成对应平台的机器码
  • 最后平台执行机器码运行程序。

面试必问之JVM原理

Java虚拟机详解(一)------简介




二、概述

1. 概念

 java虚拟机,在实际的计算机上仿真模拟各种计算机功能。

2. 思维导图

在这里插入图片描述

3.jvm位置图

在这里插入图片描述

4. jvm体系结构

4.1 简图

高效记忆:JVM架构简图
(1)头发:头上的假发(.java File)被发卡(.class File)卡得非常热(class loader
(2)眼睛:眼睛看到很多深圳本地(**本地方法栈)**人站()在大街上,人多的计数器(计数器)都算不过来,原来周杰伦来开演唱会了!
(3)耳朵:耳朵没有办法(方法区)听到外面的声音,因为房子是全部用隔音墙堆()的。
(4)鼻子:我的鼻子直接(直接内存)闻到了很远(元数据区)的红烧牛肉的味道,太香了!
(5)嘴巴:我用本地方法(本地方法库)吃东莞烧鹅,然后直接口(本地方法接口)吃了,最后无法执行(执行引擎)今天的演讲任务了。

在这里插入图片描述

4.2 详细图

在这里插入图片描述

5.ClassLoader(类加载器)

5.1 类加载

5.1.1 概念

(1)Java File 文件经过编译后变成 .class File字节码文件
(2)class File字节码文件通过类加载器加载到 JVM 虚拟机中。

5.2 类加载

5.2.1流程图
高效记忆 :类加载流程
(1)今天我太无聊了,于是下载(加载)了抖音安装包,安装抖音的时候,手机会先验证(验证)安装包的安全性。
(2)安装好后抖音会做好自启动、开启定位等准备(准备),然后会解析(解析)我的用户名和密码等信息,最后初始化(初始化)信息。
(3)当我使用(使用)一天后觉得浪费了太多时间,于是又把抖音卸载(卸载)了。
上述可以结合自己对具体过程联合记忆,如:
加载:加了2个擂(2进制类)台,擂台上东西堆成了卡车模特队形象。(class对象)
验证:验证文件格式中是否有字节码、引用符号
准备:准备嫁给变态(静态变量)却被默认(初始默认值)了
解析:引用符号直接引用
初始化:变态被赋予正确的初始价值

在这里插入图片描述

5.2.2 顺序

(1)加载、验证、准备和初始化这4个阶段发生的顺序是确定的,而解析阶段则不一定。
(2)解析可以在初始化之后开始,是为了支持 Java 语言的运行时绑定
(3)另外这5个阶段是按顺序开始,而不是按顺序进行或完成。
(4)这些阶段通常都是互相交叉地混合进行,通常在一个阶段执行的过程中调用或激活另一个阶段。

5.2.3 概述

(1)加载:查找并加载类的二进制数据,在 Java 堆中创建一个 java.lang.Class 类的对象;

(2)连接:连接包含:验证、准备、初始化;

  • 验证:文件格式、元数据、字节码、符号引用验证;
  • 准备:为类的静态变量分配内存,并将其初始化为默认值;
  • 解析:把类中的符号引用转换为直接引用。

(3)初始化:为类的静态变量赋予正确的初始值;

  • BootStrap ClassLoader:rt.jar
  • Extention ClassLoader:加载扩展的 jar 包
  • App ClassLoader:指定的 classpath 下面的 jar包
  • Custom ClassLoader:自定义的类加载器

(4)使用:new出对象程序中使用;

(5)卸载:执行垃圾回收。

5.3 类加载器

高效记忆:类加载分类
我引导(引导类加载器)爸妈扩展了 (扩展类加载器)微信聊天应用(应用类加载器)的用户自定义表情(用户自定义类加载器)。
5.3.1 启动/引导类加载器

Bootstrap

(1)主要加载的是JVM自身需要的类,使用C++语言实现,
(2)负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中
,只加载包名为java、javax、sun等开头的类。

5.3.2 扩展类加载器

Extension
(1)加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,开发者可以直接使用
(2)一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

5.3.3 系统/应用类加载器

System、Application

5.3.4 用户自定义加载器

Custom

5.4 类加载实例

5.4.1 图

在这里插入图片描述

5.4.2 获取类加载器的代码
class Person{
}


public class TestClassLoader {
    public static void main(String[] args) {

        Person person_01 = new Person();
        Person person_02 = new Person();
        Person person_03 = new Person();

        //发现person_01,person_02,person_03的hashCode一致,代表这三个实例化对象隶属于一个Class,即Person
        System.out.println(person_01.hashCode());
        System.out.println(person_02.hashCode());
        System.out.println(person_03.hashCode());

        //Person实例化对象person_01通过getClass()方法得到Class对象Person
        Class Person = person_01.getClass();
        //Person通过getClassLoader()方法得到系统类加载器
        ClassLoader myClassLoader = Person.getClassLoader();
        System.out.println(myClassLoader.hashCode());
        //加载器对象myClassLoader通过getParent()方法得到拓展类加载器
        ClassLoader myParentClassLoader = myClassLoader.getParent();
        System.out.println(myParentClassLoader.hashCode());
        //加载器对象myGPClassLoader通过getParent()方法得到引导类加载器
        ClassLoader myGPClassLoader = myParentClassLoader.getParent();
        System.out.println(myGPClassLoader.hashCode()); //发现报错,无法通过方法获取引导类加载器
    }

}

6.双亲委派机制

6.1 类加载器间关系图

在这里插入图片描述
备注
 父类加载器并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码。

6.2 工作原理

高效记忆:双亲委派原理
(1)子类(类加载器)班级学生会收到校外联谊请求(类加载请求)访问后,不是自己班级学生会先去决定并执行(加载执行)接待,而是先委托给父类(父类加载器)系级学生会去决定接待,
(2)如果父类(父类加载器)系级学生会还有父类(父类加载器)院级学生会,则进一步向上委托,直到顶级父类(顶级类加载器)总学生会。
(3)父类(父类加载器)总学生会决定接待后,如果需要父类(父类加载器)总学生会执行接待,就由父类(父类加载器)总学生会直接执行接待
(4)如果父类(父类加载器)总学生会不需要亲自执行接待,则让他子类(子类加载器)院级学生会去执行接待。

(1)一个类加载器收到类加载请求后并不会自己先去加载,而是把请求委托给父类的加载器去执行
(2)如果父类加载器还存在其父类加载器,则进一步向上委托直到顶级类加载器,
(3)如果父类加载器完成类加载,就成功返回
(4)如果父类加载器未完成类加载,其子类加载器就会去加载。

6.3 优点

(1)确保类只被加载一次, 避免重复加载
(2)用户即使自定义同样路径的java.lang.Integer类,最后加载还是jdk的Integer类。
避免了恶意篡改核心包的风险。

7.沙箱安全机制

7.1 概念

(1)将 Java 代码限定在虚拟机特定的运行范围中,并且严格限制代码对本地系统资源访问。
(2)保证对代码的有效隔离,防止对本地系统造成破坏。
(3)沙箱主要限制CPU、内存、文件系统、网络等系统资源访问。

7.2 沙箱的基本组件

7.2.1 字节码校验器(bytecode verifier)

(1)确保Java类文件遵循Java语言规范,帮助Java程序实现内存保护
(2)核心类等不用经过字节码校验

7.2.2 类加载(class loader)

(1)防止恶意代码去干涉善意的代码;
(2)守护了被信任的类库边界;
(3)将代码归入保护域,确定了代码可以进行哪些操作。

三、JVM详解

运行时数据区域

(1)Java 程序在运行时,会为 JVM 单独划出一块内存区域。
(2)这块内存区域又可以再次划分出一块运行时数据区,含以下五个部分:
在这里插入图片描述

  • 栈和本地方法栈和计数器都是独享区域,不存在线程安全问题。
  • 方法区,堆都为线程共享区域,有线程安全问题。
  • JVM 的调优主要围绕栈、堆两大块进行。
高效记忆:JVM运行区数据类型
(1)我在客栈(栈)里的8(8大基本数据类型)个对象饮用(对象引用)青梅煮酒,
(2)因为不讲究喝酒方法(方法区)醉的一塌糊涂,最后躺在敞亮水池(常量、运行时常量池)中,累的没有办法起来(类、方法),
(3)等我醒来发现,前面都是我变态(静态变量、字符串常量池)地堆(堆)集的梦里new出来的对象(new的对象实例)

1.本地方法栈(Native)

Native Method Stack

1.1 本地方法

(1)凡是带了native关键字的,说明java的作用范围达不到了,回去调用底层c语言的库!
(2)会进入本地方法栈,然后去调用本地方法接口将native方法引入执行

1.2 本地方法栈

(1)线程独享区,负责登记native方法
(2)在执行引擎( Execution Engine )执行的时候,通过本地方法接口(JNI)加载本地方法库中的方法。
(3)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常;
(4)如果虚拟机栈可以动态扩展,当扩展时无法申请到足够的内存时会抛出 OutOfMemoryError异常。

2.虚拟机栈:简称栈

2.1 概述

(1)线程私有,每个线程独享一个虚拟机栈,生命周期与线程相同。
(2)描述Java 方法执行的内存模型:

  • 每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)
  • 栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。
  • 每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
    (3)栈内存主管程序的运行、生命周期和线程同步。线程结束,栈内存就释放,不存在垃圾回收问题。
    (4)栈内存中运行:8大基本类型+对象引用.
    (5)与本地方法栈一样,虚拟机栈区域也会抛出 StackOverflowError 和 OutOfMemoryError 异常。

2.2 栈图

在这里插入图片描述

2.3 栈流程

2.3.1 流程概述
例:int a=7

(1)局部变量表:存放局部变量(a)

(2)操作数栈:存放操作数(7)

(3)动态链接:将符号引用转成直接引用(符号引用就是你知道调用了谁,直接引用就是你拿到将要要调用的方法的地址)

(4)方法出口:方法结束

2.3.2 流程图

在这里插入图片描述

3.PC程序计数器

(1)线程私有,每个线程都有一个。
(2)记录当前线程所执行的位置。
(3)当线程获得 CPU 的执行权的时候,就直接从记录的位置开始执行。
分支、循环、跳转、异常处理也都依赖这个程序计数器来完成。

4.方法区(Method Area)

(1)所有线程共享区域,线程不安全区域。
(2)存储已被虚拟机加载的类、方法信息等,如类信息(构造方法、接口定义)(Class)、常量(final)、运行时常量池、即时编译器编译后的代码等数据。但是实例变量存在堆内存中
(3)无法满足内存分配需求时,将抛出 OutOfMemoryError 异常。

5.堆

5.1 概述

(1)线程共享区域,因此是线程不安全的。
(2)一个JVM只有一个堆内存,堆内存的大小是可以调节的
(3)存储的是我们 new 来的对象即对象实例,不存放基本类型和对象引用。
(4)JDK1.8及之后,把静态变量、字符串常量池也放在堆中。
(5)由于创建了大量的对象,垃圾回收器主要工作在这块区域;
(6)会发生 OutOfMemoryError

5.2 结构图

在这里插入图片描述
在这里插入图片描述

5.3 新生区

5.3.1 概念

类的诞生,成长和死亡的地方

5.3.2 组成

(1)伊甸园区:所有对象都在伊甸园区new出来
(2)幸存0区和幸存1区:轻GC之后存下来的

5.4 老年区(养老区)

多次轻GC存活下来的对象放在老年区

8.5 永久区

方法区的实现区,jdk1.8后称为元空间:逻辑上存在,物理上不存在 ,因为:存储在本地磁盘内,不占用虚拟机内存
在这里插入图片描述
在这里插入图片描述

9.总结

(1)栈:基本类型的变量,对象的引用变量
(2)方法区:常量及运行时常量池、类型信息、字段、方法
(3)堆:存放由new创建的对象、静态变量、及字符串常量池

备注: 默认情况下,JVM使用的最大内存为电脑总内存的四分之一,JVM使用的初始化内存为电脑总内存的六十四分之一.


一篇跳转—JVM(二)垃圾回收及收集器


参考链接1

参考链接2


随心所往,看见未来。Follow your heart,see night!

*欢迎点赞、关注、留言,收藏及转发,一起学习、交流!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值