【JVM详解二】常量池

一、常量池概述

JVM的常量池主要有以下几种:
  • class文件常量池
  • 运行时常量池
  • 字符串常量池
  • 基本类型包装类常量池
它们相互之间关系大致如下图所示:
  1. 每个 class 的字节码文件中都有一个常量池,里面是编译后即知的该 class 会用到的字面量与符号引用,这就是 class 文件常量池。JVM加载 class ,会将其类信息,包括 class 文件常量池置于方法区中。
  2. class 类信息及其 class 文件常量池是字节码的二进制流,它代表的是一个类的静态存储结构,JVM加载类时,需要将其转换为方法区中的 java.lang.Class 类的对象实例;同时,会将 class 文件常量池中的内容导入运行时常量池。
  3. 运行时常量池中的常量对应的内容只是字面量,比如一个"字符串",它还不是 String 对象;当 Java 程序在运行时执行到这个"字符串"字面量时,会去字符串常量池里找该字面量的对象引用是否存在,存在则直接返回该引用,不存在则在Java堆里创建该字面量对应的 String 对象,并将其引用置于字符串常量池中,然后返回该引用。
  4. Java的基本数据类型中,除了两个浮点数类型,其他的基本数据类型都在各自内部实现了常量池,但都在[-128~127]这个范围内。

二、class文件常量池

java的源代码 .java 文件在编译之后会生成 .class 文件,class 文件需要严格遵循 JVM 规范才能被 JVM 正常加载,它是一个二进制字节流文件,里面包含了class文件常量池的内容。

class文件常量池诞生于编译时,存在于class文件中,存放符号引用和字面量。

2.1 查看一个class文件内容

jdk 提供了 javap 命令,用于对class文件进行反汇编,输出类相关信息。该命令用法如下:

用法: javap <options> <classes>
其中, 可能的选项包括:-help  --help  -?        输出此用法消息-version                 版本信息-v  -verbose             输出附加信息-l                       输出行号和本地变量表-public                  仅显示公共类和成员-protected               显示受保护的/公共类和成员-package                 显示程序包/受保护的/公共类和成员 (默认)-p  -private             显示所有类和成员-c                       对代码进行反汇编-s                       输出内部类型签名-sysinfo                 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)-constants               显示最终常量-classpath <path>        指定查找用户类文件的位置-cp <path>               指定查找用户类文件的位置-bootclasspath <path>    覆盖引导类文件的位置

例如,我们可以编写一个简单的类,如下:

public class Student {private final String name = "张三";private final int entranceAge = 18;private String evaluate = "优秀";private int scores = 95;private Integer level = 5;public String getEvaluate() {return evaluate;}public void setEvaluate(String evaluate) {String tmp = "+";this.evaluate = evaluate + tmp;}public int getScores() {return scores;}public void setScores(int scores) {final int base = 10;System.out.println("base:" + base);this.scores = scores + base;}public Integer getLevel() {return level;}public void setLevel(Integer level) {this.level = level;}
}

对其进行编译和反汇编:

javac Student.java
javap -v Student.class
# over

得到以下反汇编结果:

Classfile /home/work/sources/open_projects/lib-zc-crypto/src/test/java/Student.classLast modified 2021-1-4; size 1299 bytesMD5 checksum 06dfdad9da59e2a64d62061637380969Compiled from "Student.java"
public class Studentminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref          #19.#48        // java/lang/Object."<init>":()V#2 = String             #49            // 张三#3 = Fieldref           #18.#50        // Student.name:Ljava/lang/String;#4 = Fieldref           #18.#51        // Student.entranceAge:I#5 = String             #52            // 优秀#6 = Fieldref           #18.#53        // Student.evaluate:Ljava/lang/String;#7 = Fieldref           #18.#54        // Student.scores:I#8 = Methodref          #55.#56        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#9 = Fieldref           #18.#57        // Student.level:Ljava/lang/Integer;#10 = String             #58            // +#11 = Class              #59            // java/lang/StringBuilder#12 = Methodref          #11.#48        // java/lang/StringBuilder."<init>":()V#13 = Methodref          #11.#60        // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#14 = Methodref          #11.#61        // java/lang/StringBuilder.toString:()Ljava/lang/String;#15 = Fieldref           #62.#63        // java/lang/System.out:Ljava/io/PrintStream;#16 = String             #64            // base:10#17 = Methodref          #65.#66        // java/io/PrintStream.println:(Ljava/lang/String;)V#18 = Class              #67            // Student#19 = Class              #68            // java/lang/Object#20 = Utf8               name#21 = Utf8               Ljava/lang/String;#22 = Utf8               ConstantValue#23 = Utf8               entranceAge#24 = Utf8               I#25 = Integer            18#26 = Utf8               evaluate#27 = Utf8               scores#28 = Utf8               level#29 = Utf8               Ljava/lang/Integer;#30 = Utf8               <init>#31 = Utf8               ()V#32 = Utf8               Code#33 = Utf8               LineNumberTable#34 = Utf8               getEvaluate#35 = Utf8               ()Ljava/lang/String;#36 = Utf8               setEvaluate#37 = Utf8               (Ljava/lang/String;)V#38 = Utf8               getScores#39 = Utf8               ()I#40 = Utf8               setScores#41 = Utf8               (I)V#42 = Utf8               getLevel#43 = Utf8               ()Ljava/lang/Integer;#44 = Utf8               setLevel#45 = Utf8               (Ljava/lang/Integer;)V#46 = Utf8               SourceFile#47 = Utf8               Student.java#48 = NameAndType        #30:#31        // "<init>":()V#49 = Utf8               张三#50 = NameAndType        #20:#21        // name:Ljava/lang/String;#51 = NameAndType        #23:#24        // entranceAge:I#52 = Utf8               优秀#53 = NameAndType        #26:#21        // evaluate:Ljava/lang/String;#54 = NameAndType        #27:#24        // scores:I#55 = Class              #69            // java/lang/Integer#56 = NameAndType        #70:#71        // valueOf:(I)Ljava/lang/Integer;#57 = NameAndType        #28:#29        // level:Ljava/lang/Integer;#58 = Utf8               +#59 = Utf8               java/lang/StringBuilder#60 = NameAndType        #72:#73        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#61 = NameAndType        #74:#35        // toString:()Ljava/lang/String;#62 = Class              #75            // java/lang/System#63 = NameAndType        #76:#77        // out:Ljava/io/PrintStream;#64 = Utf8               base:10#65 = Class              #78            // java/io/PrintStream#66 = NameAndType        #79:#37        // println:(Ljava/lang/String;)V#67 = Utf8               Student#68 = Utf8               java/lang/Object#69 = Utf8               java/lang/Integer#70 = Utf8               valueOf#71 = Utf8               (I)Ljava/lang/Integer;#72 = Utf8               append#73 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;#74 = Utf8               toString#75 = Utf8               java/lang/System#76 = Utf8               out#77 = Utf8               Ljava/io/PrintStream;#78 = Utf8               java/io/PrintStream#79 = Utf8               println
{方法信息,此处省略...
}
SourceFile: "Student.java"

其中的 Constant pool 就是 class 文件常量池,使用 # 加数字标记每个“常量”。

2.2 class文件常量池的内容

class 文件常量池存放的是该 class 编译后即知的,在运行时将会用到的各个“常量”。注意这个常量不是编程中所说的 final 修饰的变量,而是字面量和符号引用,如下图所示:

2.2.1 字面量

字面量大约相当于Java代码中的双引号字符串和常量的实际的值,包括:

1)文本字符串

即代码中用双引号包裹的字符串部分的值。

例如刚刚的例子中,有三个字符串:"张三","优秀","+",它们在class文件常量池中分别对应:

#49 = Utf8               张三
#52 = Utf8               优秀
#58 = Utf8               +

2)用final修饰的成员变量的值

例如,private static final int entranceAge = 18;

这条语句定义了一个final常量entranceAge,它的值是18,对应在class文件常量池中就有:

#25 = Integer 18

注意,只有final修饰的成员变量如entranceAge,才会在常量池中存在对应的字面量。而非final的成员变量scores,以及局部变量base(即使使用final修饰了),它们的字面量都不会在常量池中定义。

2.2.2 符号引用

符号引用包括:

1)类和接口的全限定名

例如:

#11 = Class              #59            // java/lang/StringBuilder
#59 = Utf8               java/lang/StringBuilder

2)方法的名称和描述符

例如:

#38 = Utf8               getScores
#39 = Utf8               ()I#40 = Utf8               setScores
#41 = Utf8               (I)V

以及这种对其他类的方法的引用:

#8 = Methodref          #55.#56        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#55 = Class              #69            // java/lang/Integer
#69 = Utf8               java/lang/Integer#56 = NameAndType        #70:#71        // valueOf:(I)Ljava/lang/Integer;
#70 = Utf8               valueOf
#71 = Utf8               (I)Ljava/lang/Integer;

3)字段的名称和描述符

例如:

#3 = Fieldref           #18.#50        // Student.name:Ljava/lang/String;#18 = Class              #67            // Student
#67 = Utf8               Student#50 = NameAndType        #20:#21        // name:Ljava/lang/String;
#20 = Utf8               name
#21 = Utf8               Ljava/lang/String;

以及这种局部变量:

#64 = Utf8 base:10

三、运行时常量池

JVM在加载某个 class 的时候,需要完成以下任务:

  1. 通过该class的全限定名来获取它的二进制字节流,即读取其字节码文件。其内容包括在上文class文件常量池中介绍的class文件常量池。
  2. 将读入的字节流从静态存储结构转换为方法区中的运行时的数据结构。
  3. 在Java堆中生成该 class 对应的类对象,代表该 class 原信息。这个类对象的类型是 java.lang.Class,它与普通对象不同的地方在于,普通对象一般都是在 new 之后创建的,而类对象是在类加载的时候创建的,且是单例。

上述过程的第二步,就包含了将 class 文件常量池内容导入运行时常量池。class 文件常量池是一个 class 文件对应一个常量池,而运行时常量池只有一个,多个 class 文件常量池中的相同字符串只会对应运行时常量池中的一个字符串。

运行时常量池除了导入 class 文件常量池的内容,还会保存符号引用对应的直接引用(实际内存地址)。这些直接引用是JVM在类加载之后的链接(验证、准备、解析)阶段从符号引用翻译过来的。

此外,运行时常量池具有动态性的特征,它的内容并不是全部来源与编译后的 class 文件,在运行时也可以通过代码生成常量并放入运行时常量池。比如 String.intern() 方法(String.intern()方法的分析见下文)。

要注意的是,运行时常量池中保存的“常量”依然是字面量和符号引用。比如字符串,这里放的仍然是单纯的文本字符串,而不是 String 对象。

四、字符串常量池

字符串常量池,是 JVM 用来维护字符串实例的一个引用表。在 HotSpot 虚拟机中,它被实现为一个全局的 StringTable ,底层是一个 c++ 的 hashtable 。它将字符串的字面量作为 key ,实际堆中创建的 String 对象的引用作为 value 。

字符串常量池在逻辑上属于方法区,但 JDK1.7 开始,就被挪到了堆区。

String 的字面量被导入 JVM 的运行时常量池时,并不会马上试图在字符串常量池加入对应 String 的引用,而是等到程序实际运行时,要用到这个字面量对应的 String 对象时,才会去字符串常量池试图获取或者加入 String 对象的引用。因此它是懒加载的。

如前所述,class 文件常量池和运行时常量池中,都没有直接存储字面量对应的实际对象,比如 String 对象。那么 String 对象到底是什么时候在哪里创建的呢?

4.1 创建字符串对象的方式

4.1.1 字面量赋值

直接用双引号字面值的方式创建字符串。

String str1 = "test";
String str2 = "test";
//str1 == str2 ? true
System.out.println("str1 == str2 ? "+ (str1 == str2));

当Java虚拟机启动成功后,上面的字符串"test"的字面量已经进入运行时常量池;

然后主线程开始运行,执行到 String str1 = “test"; 这条语句时,JVM会根据运行时常量池中的这个字面量去字符串常量池寻找其中是否有该字面量对应的 String 对象的引用,注意是引用。 如果没找到,就会去 Java 堆创建一个值为 “test" 的 String 对象,并将该对象的引用保存到字符串常量池,然后返回该引用;如果找到了,说明之前已经有其他语句通过相同的字面量赋值创建了该 String 对象,直接返回引用即可。

接着执行到 String str2 = “test"; 这条语句,JVM 成功找到上一步生成的 String 对象的引用。所以 str1 == str2 返回 true。

4.1.2 new String 创建字符串

使用new String 创建字符串,会先在常量池中创建,再在堆中创建。

String str3 = new String("tony");
String str4 = "tony";
//str3 == str4 ? false
System.out.println("str3 == str4 ? " + (str3 == str4));
  • 第一句中JVM拿字面量 “tony" 去字符串常量池试图获取其对应 String 对象的引用,因为是首次执行,所以没找到,于是在堆中创建了一个 “tony" 的 String 对象,并将其引用保存到字符串常量池中,然后返回;
  • 返回之后,因为new的存在,JVM又在堆中创建了与 “tony" 等值的另一个 String 对象。
  • 因此这条语句创建了两个 String 对象,它们值相等,都是 “tony" ,但是引用(内存地址)不同,所以 str3 == str4 结果是false。

4.1.3 String.intern() 方法

String.intern() 是一个 native (本地) 方法,用来处理字符串常量池中的字符串对象引用。它的工作流程可以概括为以下两种情况:

  • 常量池中已有相同内容的字符串对象:如果字符串常量池中已经有一个与调用 intern() 方法的字符串内容相同的 String 对象,intern() 方法会直接返回常量池中该对象的引用。
  • 常量池中没有相同内容的字符串对象:如果字符串常量池中还没有一个与调用 intern() 方法的字符串内容相同的对象,intern() 方法会将当前字符串对象的引用添加到字符串常量池中,并返回该引用。

总结:

  • intern() 方法的主要作用是确保字符串引用在常量池中的唯一性。
  • 当调用 intern() 时,如果常量池中已经存在相同内容的字符串,则返回常量池中已有对象的引用;否则,将该字符串添加到常量池并返回其引用。
// 创建一个新的 "Java" 对象,并把该"Java" 对象的引用添加到字符串常量池,s1 指向该引用
String s1 = "Java";
// s2 也指向字符串常量池中 "Java" 对象的引用,和 s1 是同一个对象
String s2 = s1.intern();
// 在堆中创建一个新的 "Java" 对象,s3 指向它
String s3 = new String("Java");
// s4 指向字符串常量池中的 "Java" 对象的引用,和 s1 是同一个对象
String s4 = s3.intern();
// s1 和 s2 指向的是同一个常量池中的对象
System.out.println(s1 == s2); // true
// s3 指向堆中的对象,s4 指向字符串常量池中的对象引用,所以不同
System.out.println(s3 == s4); // false
// s1 和 s4 都指向常量池中的同一个对象
System.out.println(s1 == s4); // true

对于第14行 s1 == s4 要注意,JDK1.6和JDK1.7开始,String.intern()的执行逻辑是不一样的。

  • JDK1.6 以前 intern() 可以查找调用该 intern 的对象是否存在字符串常量池,如果存在 返回其引用;如果 不存在,则添加进去并返回引用;
  • JDK1.7及以后 intern() 查找是否存在 如果存在 则返回其引用;但是,如果字符串常量池不存在(堆区一定存在,不存在就无法调用该方法),那么就将该堆区对象的引用加入字符串常量池。

因此对于第14行 s1 == s4 ,如果是JDK1.6及以前的版本,结果就是false;而如果是JDK1.7开始的版本,结果就是true。

4.1.4 new String 相加

String str5 = new String("good") + new String("morning");
str5.intern();
String str6 = "goodmorning";
//str5 == str6 ? true str5 == str5.intern() ? true
System.out.println("str5 == str6 ? " + (str5 == str6) + " str5 == str5.intern() ? " + (str5 == str5.intern()));

第一句会分别把不在常量池的"good"和"morning"两个常量对象加入常量池,拼接起来"goodmorning"不在常量池,而"goodmorning"并不会在常量池中创建常量或引用。str5.intern()检查常量池是否有字符串"goodmorning",没有,把引用添加到常量池中,str6检查常量池有字符串"goodmorning",返回它的引用,所以两个判断的结果都是true。

String str5 = new String(“good”) + new String(“morning”) 被JVM编译优化后后如下:

String str5 = (new StringBuilder()).append(new String("good")).append(new String("morning")).toString();

底层是一个StringBuilder在进行把两个对象拼接在一起,最后栈中str5指向堆中的"goodmorning",其实是StringBuilder对象:

4.2 字符串常量池是否会被GC

字符串常量池本身不会被GC,但其中保存的引用所指向的 String 对象们是可以被回收的。否则字符串常量池总是"只进不出",那么很可能会导致内存泄露。

在 HotSpot 的字符串常量池实现 StringTable 中,提供了相应的接口用于支持GC,不同的GC策略会在适当的时候调用它们。一般实在Full GC的时候,额外调用StringTable的对应接口做可达性分析,将不可达的String对象的引用从StringTable中移除掉并销毁其指向的String对象。

五、封装类常量池

除了字符串常量池,Java 的基本类型的封装类大部分也都实现了常量池。包括 Byte、Short、Integer、Long、Character、Boolean,注意,浮点数据类型Float、Double是没有常量池的。

封装类的常量池是在各自内部类中实现的,比如 IntegerCache(Integer的内部类),自然也位于堆区。

要注意的是,这些常量池是有范围的:

  • Byte , Short , Integer , Long : [-128~127]
  • Character : [0~127]
  • Boolean : [True, False]

例如下面的代码,注意其结果:

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2); //trueInteger i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4); //falseInteger i5 = -128;
Integer i6 = -128;
System.out.println(i5 == i6); //trueInteger i7 = -129;
Integer i8 = -129;
System.out.println(i7 == i8); //false

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/69342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能入门 数学基础 线性代数 笔记

必备的数学知识是理解人工智能不可或缺的要素&#xff0c;今天的种种人工智能技术归根到底都建立在数学模型之上&#xff0c;而这些数学模型又都离不开线性代数&#xff08;linear algebra&#xff09;的理论框架。 线性代数的核心意义&#xff1a;世间万事万物都可以被抽象成某…

C# Winform怎么设计串口,客户端和相机控件界面显示

首先我们必须把这个类创建好 INIAPI using System; using System.Text; using System.Runtime.InteropServices;namespace Ini {public class IniAPI{#region INI文件操作/** 针对INI文件的API操作方法&#xff0c;其中的节点&#xff08;Section)、键&#xff08;KEY&#x…

在 Windows 上使用 ZIP 包安装 MySQL 的详细步骤

以下是使用官方 ZIP 包在 Windows 上安装 MySQL 的详细步骤&#xff0c;确保能通过 mysql -uroot -p 成功连接。 步骤 1&#xff1a;下载 MySQL ZIP 包 访问 MySQL 官方下载页面&#xff1a; https://dev.mysql.com/downloads/mysql/选择 Windows (x86, 64-bit), ZIP Archive&…

el-table表格点击单元格实现编辑

使用 el-table 和 el-table-column 创建表格。在单元格的默认插槽中&#xff0c;使用 div 显示文本内容&#xff0c;单击时触发编辑功能。使用 el-input 组件在单元格中显示编辑框。data() 方法中定义了 tableData&#xff0c;tabClickIndex: null,tabClickLabel: ,用于判断是否…

Windows逆向工程入门之汇编环境搭建

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 Visual Studio逆向工程配置 基础环境搭建 Visual Studio 官方下载地址安装配置选项(后期可随时通过VS调整) 使用C的桌面开发 拓展可选选项 MASM汇编框架 配置MASM汇编项目 创建新项目 选择空…

手写一个C++ Android Binder服务及源码分析

手写一个C Android Binder服务及源码分析 前言一、 基于C语言编写Android Binder跨进程通信Demo总结及改进二、C语言编写自己的Binder服务Demo1. binder服务demo功能介绍2. binder服务demo代码结构图3. binder服务demo代码实现3.1 IHelloService.h代码实现3.2 BnHelloService.c…

DeepSeekMoE 论文解读:混合专家架构的效能革新者

论文链接&#xff1a;DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models 目录 一、引言二、背景知识&#xff08;一&#xff09;MoE架构概述&#xff08;二&#xff09;现有MoE架构的问题 三、DeepSeekMoE架构详解&#xff08;一&a…

[每周一更]-(第133期):Go中MapReduce架构思想的使用场景

文章目录 **MapReduce 工作流程**Go 中使用 MapReduce 的实现方式&#xff1a;**Go MapReduce 的特点****哪些场景适合使用 MapReduce&#xff1f;**使用场景1. 数据聚合2. 数据过滤3. 数据排序4. 数据转换5. 数据去重6. 数据分组7. 数据统计8.**统计文本中单词出现次数****代码…

【C++高并发服务器WebServer】-13:多线程服务器开发

本文目录 一、多线程服务器开发二、TCP状态转换三、端口复用 一、多线程服务器开发 服务端代码如下。 #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <pthread.h>s…

「vue3-element-admin」告别 vite-plugin-svg-icons!用 @unocss/preset-icons 加载本地 SVG 图标

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

C#中深度解析BinaryFormatter序列化生成的二进制文件

C#中深度解析BinaryFormatter序列化生成的二进制文件 BinaryFormatter序列化时,对象必须有 可序列化特性[Serializable] 一.新建窗体测试程序BinaryDeepAnalysisDemo,将默认的Form1重命名为FormBinaryDeepAnalysis 二.新建测试类Test Test.cs源程序如下: using System; us…

深度学习在医疗影像分析中的应用

引言 随着人工智能技术的快速发展&#xff0c;深度学习在各个领域都展现出了巨大的潜力。特别是在医疗影像分析中&#xff0c;深度学习的应用不仅提高了诊断的准确性&#xff0c;还大大缩短了医生的工作时间&#xff0c;提升了医疗服务的质量。本文将详细介绍深度学习在医疗影像…

计算机领域QPM、TPM分别是什么并发指标,还有其他类似指标吗?

在计算机领域&#xff0c;QPM和TPM是两种不同的并发指标&#xff0c;它们分别用于衡量系统处理请求的能力和吞吐量。 QPM&#xff08;每分钟请求数&#xff09; QPM&#xff08;Query Per Minute&#xff09;表示每分钟系统能够处理的请求数量。它通常用于衡量系统在单位时间…

【安当产品应用案例100集】036-视频监控机房权限管理新突破:安当windows操作系统登录双因素认证解决方案

一、机房管理痛点&#xff1a;权限失控下的数据泄露风险 在智慧城市与数字化转型浪潮下&#xff0c;视频监控系统已成为能源、金融、司法等行业的核心安防设施。然而&#xff0c;传统机房管理模式中&#xff0c;值班人员通过单一密码即可解锁监控画面的操作漏洞&#xff0c;正…

Unity抖音云启动测试:如何用cmd命令行启动exe

相关资料&#xff1a;弹幕云启动&#xff08;原“玩法云启动能力”&#xff09;_直播小玩法_抖音开放平台 1&#xff0c;操作方法 在做云启动的时候&#xff0c;接完发现需要命令行模拟云环境测试启动&#xff0c;所以研究了下。 首先进入cmd命令&#xff0c;CD进入对应包的文件…

< OS 有关 > 利用 google-drive-ocamlfuse 工具,在 Ubuntu 24 系统上 加载 Google DRIVE 网盘

Created by Dave On 8Feb.2025 起因&#xff1a; 想下载 StableDiffusion&#xff0c;清理系统文件时把 i/o 搞到 100%&#xff0c;已经删除到 apt 缓存&#xff0c;还差 89MB&#xff0c;只能另想办法。 在网上找能不能挂在 Google 网盘&#xff0c;百度网盘&#xff0c;或 …

【LITS游戏——暴力DFS+剪枝优化】

题目 代码 #include <bits/stdc.h> using namespace std; using pll pair<int, int>; #define x first #define y second const int N 51; pll d[4][4][4] {{{{0, 0}, {1, 0}, {2, 0}, {2, 1}}, {{0, 0}, {1, 0}, {1, -1}, {1, -2}}, {{0, 0}, {0, 1}, {1, 1},…

Redisson全面解析:从使用方法到工作原理的深度探索

文章目录 写在文章开头详解Redisson基本数据类型基础配置字符串操作列表操作映射集阻塞队列延迟队列更多关于Redisson详解Redisson 中的原子类详解redisson中的发布订阅模型小结参考写在文章开头 Redisson是基于原生redis操作指令上进一步的封装,屏蔽了redis数据结构的实现细…

用Python进行websocket接口测试

这篇文章主要介绍了用Python进行websocket接口测试&#xff0c;帮助大家更好的理解和使用python&#xff0c;感兴趣的朋友可以了解下 我们在做接口测试时&#xff0c;除了常见的http接口&#xff0c;还有一种比较多见&#xff0c;就是socket接口&#xff0c;今天讲解下怎么用P…

【RocketMQ 存储】- 同步刷盘服务 GroupCommitService

文章目录 1. 前言2. 参数3. 队列相关4. 核心逻辑 run4.1 waitForRunning4.2 doCommit4.3 flush 5. 小结 本文章基于 RocketMQ 4.9.3 1. 前言 RocketMQ 存储部分系列文章&#xff1a; 【RocketMQ 存储】- RocketMQ存储类 MappedFile【RocketMQ 存储】- 一文总结 RocketMQ 的存…