JVM--虚拟机

JVM,即虚拟机,可以简单理解为将字节码文件翻译成机器码的机器。

.class文件-->机器码文件

JVM整体组成部分

1.类加载器

负责从磁盘中加载字节码文件到JVM中

2.运行时数据区

按照不同的数据分区进行存储(方法区,堆,栈,本地方法栈,程序计数器)

3.执行引擎

把字节码编译成机器码

4.本地库接口

负责调用本地操作系统方法

类加载器子系统

概述

类加载器子系统

字节码文件**----->** 加载阶段**-->链接阶段-->初始化阶段**

类加载器子系统负责从硬盘或者网络中加载字节码文件,类加载器只负责加载,是否能运行由运行引擎决定,加载的类信息存放在方法区

抽象理解:

字节码文件放在磁盘中,可以理解成一个模版设计草图,而加载到JVM中,就要编译成工程的图纸,工厂就能按照这个图纸实例出多个实例出来。
字节码文件加载到 JVM 中,被称为 DNA 元数据模板.

类加载过程

链接

加载 ------->验证---->准备---->解析 ------>初始化

1.加载

以二进制流的方式加载字节码,

在内存中为类生成一个Class类的对象,将静态存储转成运行时存储

(从硬盘到内存)

2.链接

验证

验证字节码格式是否正确

验证语法是否正确

准备

该阶段负责为类的静态属性分配内存,并设置初始值

这里的初始值与后面初始化阶段不同,这里是准备阶段

static a = 10;

在准备阶段设置的初始值为0;

在后面初始化阶段重新赋值为10;

解析

将静态文件中的指令符号引用 替换成 内存中直接引用

int a = 10; ----------> istore_1

字节码指令 到 内存操作指令

3.初始化

对类中静态变量进行赋值

类什么时候会被加载(初始化)?

1.使用类中的静态变量,静态方法

2.在一个类中运行main

3.创建对象

4.使用反射加载一个类

5.加载其子类时,会优先加载父类

加载类中静态常量时不会被初始化,静态常量在编译期间就被初始化赋值了

当类在加载阶段初始化完成,才能说类的整个加载过程结束。

类加载器

真正加载类,是加载类的实施者

分类

jvm角度分为

1.引导类加载器(启动类加载器),非java类语言编写,c/c++,jvm底层实现

2.其他类加载器,使用java语言实现,都继承java.lang.ClassLoader

开发者角度分为:

1.引导类加载器(启动类加载器)

java中系统提供的类,都是由启动类加载器加载的,如String类

2.扩展类加载器

Java语言编写,由Launcher$ExtClassLoader实现,派生与ClassLoader类

3.应用程序类加载器

Java语言编写,由Luncher$AppClassLoader实现,派生于ClassLoader类

加载程序员自己定义的类

4.自定义类加载器

自己编写的类继承ClassLoader类

双亲委派机制

1.如果一个类加载器收到加载请求,首先他会奖盖请求委托给父级类加载器;

2.如果该父级类加载器还有父级,就继续向上委托,直到启动类加载器;

3.如果父级类加载器可以完成该类的加载任务,就成功返回,否则依次向下级委托加载

优点:避免了用户自己编写的类替换了JAVA的核心类,例如:String类,Integer类等。

打破双亲委派

通过自定义的类加载器,重写类加载器中的findClass()方法

从而打破双亲委派

运行时数据区

1.程序计数器

记录程序执行的指令的位置用的(简单理解为记录程序运行到哪了)

特点:

内存小,运行速度快,线程私有(每个线程都有一个计数器)

生命周期与线程一致

不存在内存溢出与垃圾回收

2.虚拟机栈

栈是运行单位,管理方法(java方法)的运行(也就是解决程序的运行问题)

调用方法即入栈,运行完即出栈

栈是线程私有的,不存在垃圾回收,但是会出现内存溢出

每个线程创建时都会创建一个虚拟机栈,每次调用一个方法入栈,都可以看做一个栈帧入栈。

一个栈帧也就对应一个方法。

栈帧的构成:

执行引擎只会对当前栈帧进行操作,调用新的方法,就会有新的栈帧被创造且被置于栈顶

局部变量表:存储定义的变量,参数等

操作数栈

方法返回地址

int a = 10;

int b = 20;

int c = a+++b;//这一步的运算就是 操作数栈

return;//记录被调用的方法位置,跟方法的返回值无关

3.本地方法栈

管理运行本地方法的地方,用于管理本地方法的调用,由C语言编写

常见的本地方法:用native 关键字修饰,没有方法体

hashCode();

getClass();

clone();

notify();

wait();

在本地方法栈中登记本地方法,在执行时加载本地方法库;

线程私有的,会出现内存溢出,不存在垃圾回收

4.堆(存储空间)

存放程序运行中产生的对象

运行时数据区最大的一块空间,大小可以调节(jvm调优)

线程共享,会出现内存溢出,存在垃圾回收(垃圾回收的重点区域)

4.1堆内存区域划分

新生区

伊甸园Eden:新创建的对象放在这

幸存者1:存放伊甸园区与另一个幸存者区经过垃圾回收后存会的对象

幸存者2:

两个幸存者区交替使用,始终有一个区域是空闲的

老年区

存放生命周期长的对象或者大的对象

生命周期长即经历过15次垃圾回收依然存活的对象就会被放在老年区

4.2分区的作用

可以根据不同对象的存活时间进行划分,生命较长的对象放入老年代,

从而减少垃圾回收的频率与扫描次数

当一个对象经过垃圾回收15次时依然存活就会将该对象放入老年区;

这里有人会问了为什么是15次?不是10次,20次?

在对象头有4bit位用来记录回收次数,可以设置回收次数,默认是15(1111)

新生代与老年代的比例为1:2

伊甸园与幸存者1和幸存者2的比例为8:1:1

4.3堆空间的参数设置

涉及JVM调优
jvm调优:根据程序实际运行的需要设置参数,调整各个区间比例大小
-XX:+PrintFlagsInitial查看所有参数的默认初始值
-Xms:初始堆空间内存
-Xmx:最大堆空间内存
-Xmn:设置新生代的大小
-XX:MaxTenuringTreshold:设置新生代垃圾的最大年龄
-XX:+PrintGCDetails 输出详细的 GC 处理日志

垃圾回收:
MInor GC:新生区垃圾回收 频繁
Major GC:老年区垃圾回收 较少
FULL GC:整堆垃圾回收 尽可能避免

5.方法区

主要存储加载到虚拟机的类信息,

大小可以调整(-XX:MetaspaceSize)

线程共享,存在内存溢出,存在垃圾回收(条件苛刻)

同时满足以下3个条件才会进行垃圾回收:

1.这个类的所有对象以及子类对象都被销毁

2.加载这个类的类加载器也被销毁

3.这个类的Class对象没哟被引用(主要是反射)

本地方法接口

1.什么是本地方法?

就是一个JAVA调用非JAVA代码的接口;

用native关键字修饰(不与abstart连用),没有方法体,由非JAVA语言实现;

实现体是由非JAVA语言(操作系统)在外面实现的。

2.为什么要使用本地方法?

与JAVA环境外进行交互;因为上层高级语言没有对底层硬件进行直接操作的权限,

需要调用操作系统提供的接口进行访问。

执行引擎

JVM核心组成部分之一,

负责将加载到JVM中的字节码指令解释/编译成对应平台上的本地机器指令。

类加载器子系统:把.Class文件加载到JVM中

执行引擎:把.Class文件编译成机器指令

1.概念区分

解释执行:

用解释器对代码逐行进行解释执行,

效率低,但不需要编译

编译执行:将某段代码进行整体编译,执行编译后的结果

编译花费时间,但是执行效率高

2.JAVA的半解释半编译

程序刚开始运行时采用逐行解释执行;

运行过程中,会将热点(高频)代码编译并缓存起来了(后面用到直接会用运行后的结果即可);

两者结合,提高效率

垃圾回收

垃圾:程序运行中没有被任何引用的对象

不回收会导致内存溢出OOM

早期垃圾回收需要程序员手动实现,如果忘记回收,会导致内存泄露。

怎么回收?

垃圾收集器可以对新生代,老年代进行回收,什么对全栈,方法区都可以进行垃圾回收。

**内存溢出:**经过垃圾回收,内存依然不够使用,造成程序崩溃

内存不够用

**内存泄露:**对象在程序中不会被使用,但是又不能被垃圾回收器回收,在一直占用内存,最 终导致内存溢出

内存被垃圾占用

单例模式中的单例对象

collection

socket

IO

这些资源通道没有及时关闭,垃圾回收器不能进行回收,就会造成内存泄漏。

STW(Stop The World)

指垃圾回收过程中会产生应用程序的停顿,停顿时整个应用线程都会被暂停,这个停顿称为STW.

为什么在垃圾回收中要进行STW?

垃圾回收中要分析哪些对象是垃圾,需要被回收,如果程序中的对象引用关系在不断变化,分析结果不准确,会出现漏标,错标的问题。

垃圾回收算法

1.标记阶段(判断哪些对象是垃圾)算法

**引用计数算法(未被采用):**在对象中有一个计数属性,只要有引用指向该对象,计数器加1,有断开减1,如果计数器为0,表示此对象为垃圾。

实现简单,但技术器占用空间,加减计数需要时间开销,并且无法解决循环引用问题

**可达性分析算法:**从一些活跃对象开始搜索,与根对象相关联的对象都又被引用,与跟对象或者根对象引用链不相关的对象就是垃圾。

那些对象可以作为根对象Root?

虚拟机栈中 被引用的对象

类中的静态属性

用作同步锁的对象

JAVA系统中的类
finalization机制

当对象被判定为垃圾,被回收前会调用一次finalize();

由垃圾回收机制调用。
虚拟机中对象的三种状态

1.可触及的:在根节点的引用链上

2.可复活的:垃圾回收时没调用过finalize()的

3.不可触及的: 垃圾回收时已经调用过finalize()的

对象不可触及时会被垃圾回收器回收

2.回收阶段算法

标记-复制算法

可以有多块内存,每次有一块是空的,将存活的对象复制一份到未被使用的内存中,然后清除其他块中的垃圾对象。

内存碎片少,适合存活对象少,垃圾对象多的内存(新生代)

标记-清除算法

将存活对象位置不变,将垃圾对象地址记录在一个空闲列表中,后面如果创建新的对象,就会直接覆盖掉垃圾对象

不移动对象,回收后,会产生内存碎片,效率高;适合老年代

标记-压缩算法

将存活的对象进行重新排列,排列到内存一端,将其余的内存进行清理。

要移动对象,回收后,进行压缩,不产生内存碎片,效率低;适合老年代

分代收集

根据不同区域特点进行回收,

年轻代,生命周期短,存活对象少,回收频繁,使用复制算法

老年代,生命周期长,存活对象多,回收频率低,采用清除和压缩算法混合使用。

垃圾回收器

垃圾回收器是jvm中真正进行垃圾回收的实践者,不同的厂商,不同版本实现方式都有不同。

使用时根据不同场景选择合适的垃圾回收器。

分类

从线程数量上分:

单线程Serial:适用于与一些小型设备,只有一个线程进行过垃圾回收

多线程Parallel:有多个线程进行垃圾回收

按工作数量分:

独占式:垃圾回收线程执行时,其他用户线程暂停执行

并发式:垃圾回收线程可以和用户线程一起执行

按照工作内存区间分:

老年代垃圾回收器:

新生代垃圾回收器:

GC性能指标

吞吐量:运行用户代码的时间/(运行用户代码的时间+运行垃圾收集代码的时间)

列举

回收器 线程模式 目标场景
Serial 年轻代 单线程 客户端/小内存
Serial Old 老年代 单线程 CMS 后备/小内存
ParNew 年轻代 多线程并行 低延迟(搭配 CMS)
Parallel Scavenge 年轻代 多线程并行 高吞吐量(搭配 Parallel Old)
Parallel Old 老年代 多线程并行 高吞吐量
CMS 老年代 并发 低延迟(已过时)
G1 全堆 并发 平衡吞吐量与延迟(主流)

CMS--Concurrent Mark Sweep

是首个实现垃圾实现垃圾收集线程与用户线程同时执行的;

但并不是一直都并发执行,也有独占执行

  • JDK 支持:JDK 5 引入,JDK 9 标记为废弃(Deprecated),JDK 14 移除。

初次标记:独占

并发标记:并发

重新标记:独占

并发清除:并发

G1--Garbage First

适用区域 :全堆

JDK 支持:JDK 7 引入,JDK 9+ 成为默认回收器。

内存模型:

Region 分区:将堆划分为多个大小相等的 Region(1MB~32MB)。

动态分代:Region 可动态作为 Eden、Survivor、Old 或 Humongous(存放大对象区)

工作流程:

先分区,哪个区垃圾多,优先回收那个区域

目标:平衡吞吐量与延迟

相关推荐
Aphelios3801 小时前
Java全栈面试宝典:线程机制与Spring IOC容器深度解析
java·开发语言·jvm·学习·rbac
Micro麦可乐6 小时前
最新Spring Security实战教程(七)方法级安全控制@PreAuthorize注解的灵活运用
java·spring boot·后端·spring·intellij-idea·spring security
hweiyu008 小时前
idea如何让打开的文件名tab多行显示
java·ide·intellij-idea·idea·intellij idea
数据攻城小狮子11 小时前
Java Spring Boot 与前端结合打造图书管理系统:技术剖析与实现
java·前端·spring boot·后端·maven·intellij-idea
bing_15816 小时前
JVM 每个区域分别存储什么数据?
java·jvm
zzhz92516 小时前
Jmeter(性能指标、指标插件、测试问题、面试题、讲解稿)
java·jvm·jmeter
hweiyu0016 小时前
从JVM到分布式锁:高并发架构设计的六把密钥
jvm·redis·分布式·mysql·etcd
小杨xyyyyyyy16 小时前
JVM - 垃圾回收器常见问题
java·jvm·面试
西元.16 小时前
多线程循环打印
java·开发语言·jvm
bing_15820 小时前
JVM 类加载器在什么情况下会加载一个类?
java·jvm