JVM--虚拟机
JVM,即虚拟机,可以简单理解为将字节码文件翻译成机器码的机器。
.class文件-->机器码文件
JVM整体组成部分
1.类加载器
负责从磁盘中加载字节码文件到JVM中
2.运行时数据区
按照不同的数据分区进行存储(方法区,堆,栈,本地方法栈,程序计数器)
3.执行引擎
把字节码编译成机器码
4.本地库接口
负责调用本地操作系统方法
类加载器子系统
概述
类加载器子系统
字节码文件----->加载阶段-->链接阶段-->初始化阶段
类加载器子系统负责从硬盘或者网络中加载字节码文件,类加载器只负责加载,是否能运行由运行引擎决定,加载的类信息存放在方法区
抽象理解:
字节码文件放在磁盘中,可以理解成一个模版设计草图,而加载到JVM中,就要编译成工程的图纸,工厂就能按照这个图纸实例出多个实例出来。
类加载过程
链接
加载------->验证---->准备---->解析------>初始化
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调优:根据程序实际运行的需要设置参数,调整各个区间比例大小
垃圾回收: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(存放大对象区)
工作流程:
先分区,哪个区垃圾多,优先回收那个区域
目标:平衡吞吐量与延迟
相关文章:
JVM--虚拟机
JVM,即虚拟机,可以简单理解为将字节码文件翻译成机器码的机器。 .class文件-->机器码文件 JVM整体组成部分 1.类加载器 负责从磁盘中加载字节码文件到JVM中 2.运行时数据区 按照不同的数据分区进行存储(方法区,堆,栈,本地方…...
pyside6学习专栏(八):在PySide6中使用matplotlib库绘制三维图形
本代码原来是PySide6官网的一个示例程序,我对其进行的详细的注释,同时增加了一个功能:加载显示cass的地形图坐标数据示例,示例可显示以下几种三维图形 程序运行界面如下: 代码如下: # -*- coding: utf-8 -…...
松灵机器人地盘 安装 ros 驱动 并且 发布ros 指令进行控制
安装驱动 $ cd ~/catkin_ws/src $ git clone https://github.com/agilexrobotics/ugv_sdk.git $ git clone https://github.com/agilexrobotics/scout_ros.git $ cd .. $ catkin_make安装 ● 使能 gs_usb 内核模块 ● 设置 500k 波特率和使能 can-to-usb 适配器 sudo modp…...
Highcharts 配置语法详解
Highcharts 配置语法详解 引言 Highcharts 是一个功能强大的图表库,广泛应用于数据可视化领域。本文将详细介绍 Highcharts 的配置语法,帮助您快速上手并制作出精美、实用的图表。 高级配置结构 Highcharts 的配置对象通常包含以下几部分:…...
python力扣2:两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开…...
服务器间迁移conda环境
注意:可使用迁移miniconda文件 or 迁移yaml文件两种方式,推荐前者,基本无bug! 一、迁移miniconda文件: 拷贝旧机器的miniconda文件文件到新机器: 内网拷贝:scp -r mazhf192.168.1.233:~/miniconda3 ~/ 外…...
LeetCode第58题_最后一个单词的长度
LeetCode 第58题:最后一个单词的长度 题目描述 给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中最后一个单词的长度。 单词 是指仅由字母组成、不包含任何空格字符的最大子字符串。 难度 简单 题目链接 点…...
Python 绘制迷宫游戏,自带最优解路线
1、需要安装pygame 2、上下左右移动,空格实现物体所在位置到终点的路线,会有虚线绘制。 import pygame import random import math# 迷宫单元格类 class Cell:def __init__(self, x, y):self.x xself.y yself.walls {top: True, right: True, botto…...
恶意 SSP 注入收集密码
SSP 安全服务提供者,是微软提供的与安全有关的函数接口,用户可根据自己的需求调用 SSP 接口实现高度自定义的身份验证等安全功能。攻击者注入恶意的 SSP 接口覆盖微软默认的某些安全功能,导致用户一旦进行身份验证,恶意的 SSP 将保…...
Llama 2中的Margin Loss:为何更高的Margin导致更大的Loss和梯度?
Llama 2中的Margin Loss:为何更高的Margin导致更大的Loss和梯度? 在《Llama 2: Open Foundation and Fine-Tuned Chat Models》论文中,作者在强化学习与人类反馈(RLHF)的Reward Model训练中引入了Margin Loss的概念&a…...
Python----数据分析(Numpy:安装,数组创建,切片和索引,数组的属性,数据类型,数组形状,数组的运算,基本函数)
一、 Numpy库简介 1.1、概念 NumPy(Numerical Python)是一个开源的Python科学计算库,旨在为Python提供 高性能的多维数组对象和一系列工具。NumPy数组是Python数据分析的基础,许多 其他的数据处理库(如Pandas、SciPy)都依赖于Num…...
Android Logcat 高效调试指南
工具概览 Logcat 是 Android SDK 提供的命令行日志工具,支持灵活过滤、格式定制和实时监控,官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用(通过ADB守…...
Pytest之fixture的常见用法
文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中,fixture是一个非常强大和灵活的功能,用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等, 与setup和te…...
如何把网络ip改为动态:全面指南
在数字化时代,网络IP地址作为设备在网络中的唯一标识,扮演着至关重要的角色。随着网络环境的不断变化,静态IP地址的局限性逐渐显现,而动态IP地址则因其灵活性和安全性受到越来越多用户的青睐。那么,如何把网络IP改为动…...
anythingLLM和deepseek4j和milvus组合建立RAG知识库
1、deepseek本地化部署使用 ollama 下载模型 Tags bge-m3 bge-m3:latest deepseek-r1:32b deepseek-r1:8b 2、安装好向量数据库 milvus docker安装milvus单机版-CSDN博客 3、安装 anythingLLM AnythingLLM | The all-in-one AI application for everyone …...
和鲸科技推出人工智能通识课程解决方案,助力AI人才培养
2025年2月,教育部副部长吴岩应港澳特区政府邀请,率团赴港澳宣讲《教育强国建设规划纲要 (2024—2035 年)》。在港澳期间,吴岩阐释了教育强国目标的任务,并与特区政府官员交流推进人工智能人才培养的办法。这一系列行动体现出人工智…...
当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开
现象: 查看电脑桌面下方的任务栏,明明已经关闭了WPS和WORD软件,但是打开word文档时还是提示: 解决方法步骤: 1、按一下键盘上的ctrl Shift Esc 键打开任务管理器 2、在进程中找到如下: 快速找到的方法…...
高频面试题(含笔试高频算法整理)基本总结回顾3
目录 一、基本面试流程回顾 二、基本高频算法题展示 三、基本面试题总结回顾 (一)Java高频面试题整理 (二)JVM相关面试问题整理 (三)MySQL相关面试问题整理 (四)Redis相关面试…...
Python中字符串的常用操作
一、r原样输出 在 Python 中,字符串前加 r(即 r"string" 或 rstring)表示创建一个原始字符串(raw string)。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符࿱…...
卷积神经网络(cnn,类似lenet-1,八)
我们第一层用卷积核,前面已经成功,现在我们用两层卷积核: 结构如下,是不是很想lenet-1,其实我们24年就实现了sigmoid版本的: cnn突破九(我们的五层卷积核bpnet网络就是lenet-1)-CS…...
Win32 C++ 电源计划操作
CPowerCfgUtils.h #pragma once#include <Windows.h> #include <powrprof.h>// https://learn.microsoft.com/zh-cn/windows/win32/api/powrprof/?sourcerecommendations//节能 //DEFINE_GUID(GUID_MAX_POWER_SAVINGS, 0xA1841308, 0x3541, 0x4FAB, 0xBC, 0x81, …...
PH热榜 | 2025-03-01
1. Helix 标语:从想法到原型只需3分钟 介绍:Helix可以在几分钟内将你的创业想法变成一个准备好接受投资的原型。你可以创建功能齐全、可点击的用户界面和用户体验设计,完全不需要任何设计技能。 产品网站: 立即访问 Product H…...
如何管理路由器
一、管理路由器的必要性 1、需要修改拨号上网的密码。 2、需要修改WIFI的SSID名字和密码。 3、设置DHCP协议信息。 4、设置IP地址的过滤规则。 5、给某个设备连接设置网络限速。 二、常见的方式 (一)web网页方式 1、计算机用双绞线或者WIFI的方式连接路由器。 2、在计算机中打开…...
deepseek使用记录17
基于《资本论》方法论的"35岁危机"系统分析 一、劳动力商品化与价值贬值的双重绞索 马克思揭示:“劳动力作为商品,其价值由生产劳动力所需的社会必要劳动时间决定”。在数字资本主义时代,这一规律呈现特殊形态: 技能折…...
【Java】I/O 流篇 —— 打印流与压缩流
目录 打印流概述字节打印流构造方法成员方法代码示例 字符打印流构造方法成员方法代码示例 打印流的应用场景 解压缩/压缩流解压缩流压缩流 Commons-io 工具包概述Commons-io 使用步骤Commons-io 常见方法代码示例 Hutool 工具包 打印流 概述 分类:打印流一般是指…...
Tomcat基础知识及其配置
1.Tomcat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服…...
【LeetCode】739.每日温度
目录 题目描述输入输出示例及数据范围思路:单调栈C 实现 题目描述 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这…...
测试金蝶云的OpenAPI
如何使用Postman测试K3Cloud的OpenAPI 1. 引言 在本篇博客中,我将带你逐步了解如何使用Postman测试和使用K3Cloud的OpenAPI。内容包括下载所需的SDK文件、配置文件、API调用及测试等步骤。让我们开始吧! 2. 下载所需的SDK文件 2.1 获取SDK 首先&…...
SID History 域维权
SID History 域林攻击:域林攻击详解-CSDN博客 SID History 根据微软的描述,SID History 属性是微软对域内用户进行域迁移的支持而创建的。每当对象从一个域移动到另一个域时,都会创建一个新的 SID,并且该新 SID 将成为 objectSI…...
unittest自动化测试框架详解
一、Unittest简介 Unittest是python内置的一个单元测试框架,主要用于自动化测试用例的开发与执行 简单的使用如下 import unittestclass TestStringMethods(unittest.TestCase):def setUp(self):print("test start")def test_upper(self):self.assertE…...
