当前位置: 首页 > article >正文

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(存放大对象区)

        工作流程:

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

        目标:平衡吞吐量与延迟

相关文章:

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 的配置对象通常包含以下几部分&#xff1a…...

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 提供的命令行日志工具&#xff0c;支持灵活过滤、格式定制和实时监控&#xff0c;官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用&#xff08;通过ADB守…...

Pytest之fixture的常见用法

文章目录 1.前言2.使用fixture执行前置操作3.使用conftest共享fixture4.使用yield执行后置操作 1.前言 在pytest中&#xff0c;fixture是一个非常强大和灵活的功能&#xff0c;用于为测试函数提供固定的测试数据、测试环境或执行一些前置和后置操作等&#xff0c; 与setup和te…...

如何把网络ip改为动态:全面指南

在数字化时代&#xff0c;网络IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。随着网络环境的不断变化&#xff0c;静态IP地址的局限性逐渐显现&#xff0c;而动态IP地址则因其灵活性和安全性受到越来越多用户的青睐。那么&#xff0c;如何把网络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月&#xff0c;教育部副部长吴岩应港澳特区政府邀请&#xff0c;率团赴港澳宣讲《教育强国建设规划纲要 (2024—2035 年)》。在港澳期间&#xff0c;吴岩阐释了教育强国目标的任务&#xff0c;并与特区政府官员交流推进人工智能人才培养的办法。这一系列行动体现出人工智…...

当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开

现象&#xff1a; 查看电脑桌面下方的任务栏&#xff0c;明明已经关闭了WPS和WORD软件&#xff0c;但是打开word文档时还是提示&#xff1a; 解决方法步骤&#xff1a; 1、按一下键盘上的ctrl Shift Esc 键打开任务管理器 2、在进程中找到如下&#xff1a; 快速找到的方法…...

高频面试题(含笔试高频算法整理)基本总结回顾3

目录 一、基本面试流程回顾 二、基本高频算法题展示 三、基本面试题总结回顾 &#xff08;一&#xff09;Java高频面试题整理 &#xff08;二&#xff09;JVM相关面试问题整理 &#xff08;三&#xff09;MySQL相关面试问题整理 &#xff08;四&#xff09;Redis相关面试…...

Python中字符串的常用操作

一、r原样输出 在 Python 中&#xff0c;字符串前加 r&#xff08;即 r"string" 或 rstring&#xff09;表示创建一个原始字符串&#xff08;raw string&#xff09;。下面详细介绍原始字符串的特点、使用场景及与普通字符串的对比。 特点 忽略转义字符&#xff1…...

卷积神经网络(cnn,类似lenet-1,八)

我们第一层用卷积核&#xff0c;前面已经成功&#xff0c;现在我们用两层卷积核&#xff1a; 结构如下&#xff0c;是不是很想lenet-1&#xff0c;其实我们24年就实现了sigmoid版本的&#xff1a; cnn突破九&#xff08;我们的五层卷积核bpnet网络就是lenet-1&#xff09;-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 标语&#xff1a;从想法到原型只需3分钟 介绍&#xff1a;Helix可以在几分钟内将你的创业想法变成一个准备好接受投资的原型。你可以创建功能齐全、可点击的用户界面和用户体验设计&#xff0c;完全不需要任何设计技能。 产品网站&#xff1a; 立即访问 Product H…...

如何管理路由器

一、管理路由器的必要性 1、需要修改拨号上网的密码。 2、需要修改WIFI的SSID名字和密码。 3、设置DHCP协议信息。 4、设置IP地址的过滤规则。 5、给某个设备连接设置网络限速。 二、常见的方式 (一)web网页方式 1、计算机用双绞线或者WIFI的方式连接路由器。 2、在计算机中打开…...

deepseek使用记录17

基于《资本论》方法论的"35岁危机"系统分析 一、劳动力商品化与价值贬值的双重绞索 马克思揭示&#xff1a;“劳动力作为商品&#xff0c;其价值由生产劳动力所需的社会必要劳动时间决定”。在数字资本主义时代&#xff0c;这一规律呈现特殊形态&#xff1a; 技能折…...

【Java】I/O 流篇 —— 打印流与压缩流

目录 打印流概述字节打印流构造方法成员方法代码示例 字符打印流构造方法成员方法代码示例 打印流的应用场景 解压缩/压缩流解压缩流压缩流 Commons-io 工具包概述Commons-io 使用步骤Commons-io 常见方法代码示例 Hutool 工具包 打印流 概述 分类&#xff1a;打印流一般是指…...

Tomcat基础知识及其配置

1.Tomcat简介 Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun和其他一些公司及个人共同开发而成。 Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服…...

【LeetCode】739.每日温度

目录 题目描述输入输出示例及数据范围思路&#xff1a;单调栈C 实现 题目描述 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这…...

测试金蝶云的OpenAPI

如何使用Postman测试K3Cloud的OpenAPI 1. 引言 在本篇博客中&#xff0c;我将带你逐步了解如何使用Postman测试和使用K3Cloud的OpenAPI。内容包括下载所需的SDK文件、配置文件、API调用及测试等步骤。让我们开始吧&#xff01; 2. 下载所需的SDK文件 2.1 获取SDK 首先&…...

SID History 域维权

SID History 域林攻击&#xff1a;域林攻击详解-CSDN博客 SID History 根据微软的描述&#xff0c;SID History 属性是微软对域内用户进行域迁移的支持而创建的。每当对象从一个域移动到另一个域时&#xff0c;都会创建一个新的 SID&#xff0c;并且该新 SID 将成为 objectSI…...

unittest自动化测试框架详解

一、Unittest简介 Unittest是python内置的一个单元测试框架&#xff0c;主要用于自动化测试用例的开发与执行 简单的使用如下 import unittestclass TestStringMethods(unittest.TestCase):def setUp(self):print("test start")def test_upper(self):self.assertE…...