【学习笔记】深入理解JVM之类加载机制
【学习笔记】深入理解JVM之类加载机制
以后基本上都在语雀上面更新,大家有兴趣可以看看嗷!
首发地址: 知识库
文章流程图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6mcrGx0K-1671638019183)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221221234802063.png)]](https://img-blog.csdnimg.cn/253ad4600d2a477fa08fabac75785716.png)
1、概述
首先我们先来看看一个 Class 文件所需要经过的一个流程图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SQMDXw9o-1671638019183)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218145747775.png)]](https://img-blog.csdnimg.cn/671da427c7b145f6bd748dd635da0a63.png)
而我们今天要重点需讲的就是 类加载器 这部分。
在讲类加载器之前先问一个问题——什么是
Class文件?
Class 文件是一组 8 字节为基础单位的二进制文件,各个数据项项目严格按照顺序紧凑地排列在文件之中,中间没有添加任何分隔符,这使得 Class 文件中存储的内存内容部分都是程序运行的必要数据,没有空隙存在。
通过上面的回答我们知道
Class文件,是一个以8自己为基础单位的二进制文件,那如果遇到一个需要 占用8字节以上的的空间数据项时会怎么办?
当出现占用超过 8 以上空间的数据项时,则会采用 高位在前 的方式分割成若干个 8 个字节进行存储。
补充:
一般
Class文件的头四个字节被称为 魔数(Magic Number) ,它的作用就是确定这个文件是否为一个能被虚拟机接受的Class文件。
2、类加载机制
那什么又是类加载机制呢?
Java虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行 校验、转换解析和初始化 ,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。
类加载的过程图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kgFGj2lU-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218151529117.png)]](https://img-blog.csdnimg.cn/062133dcf2fd48e19e8d93b780387249.png)
2.1 加载
注意此处的 “加载” 是 ‘’类加载“ 过程中的一个阶段, 大家不要弄混了嗷。
在加载阶段,Java 虚拟机需要完成以下三件事:
- 通过一个类的
全限定名来获取定义此类的二进制字节流。 - 将这个
字节流所代表的静态存储结构转化为方法区的运行时数据结构。 - 在内存中生成一个代表这个类的
java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
补充:
可以获取二进制字节流的方式:
- 从ZIP压缩包中读取,这很常见,最中成为日后JAR、EAR、WAR的格式基础。
- 从网络中获取,这种场景最低昂行的应用就是
Web Applet。- 运行时计算生成,这种场景使用得最多的就是 动态代理 技术,在
java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass()来为特定接口生成形式为"*$Proxy"的代理类的二进制字节流。- 从数据库中读取。
- 其他文件生成。
- …
2.2 验证
验证是链接阶段的第一步,这一阶段的目的是确保 Class 文件的字节流中包含的信息符合 《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。
举个例子:
我们知道 Class 文件并不一定都是 Java 源码编译而来,它可以使用包括靠键盘 0和1 直接在二进制编辑器中敲出 Class 文件。如果不进行此方面的验证,对其完全信任的话,可能会有恶意的企图的字节码流程,而导致整个系统搜到破坏。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Jr9QB1u-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218200905808.png)]](https://img-blog.csdnimg.cn/ea5de01f61c54c8caec44960ddc4beb5.png)
所以说验证字节码是 Java 虚拟机自我保护的一项必要措施。
验证阶段是是十分严谨的,直接决定了 Java虚拟机 是否能承受恶意代码的攻击。验证阶段大致分为以下四个阶段:
文件格式验证元数据验证字节码验证符号引用验证
♣️ 2.2.1 文件格式验证
第一阶段就是需要验证字节流是否符合 Class 文件格式的规范,并且能被当前版本的虚拟机处理。这一阶段可能包括下面这些验证点:
- 是否以魔数
0xCAFEBABE开头。 - 主、次版本号是否在当前的
Java虚拟机接受范围之内。 - 常量池的常量中是否有不被支持的常量类型。
- 指向常量的各种索引值中是否有指向不存在的常量或不符合类型的常量。
- CONSTANT_Utf8_info型的常量中是否有不符合UTF-8编码的数据。
Class文件中各个部分及文件本身是否有被删除的或附加的其他信息。- …
目的:
上述的验证阶段主要是为了保证输入的字节流能正确地解析并存储于方法区内。这个阶段是基于二进制字节流进行的,只有通过了这个阶段的验证之后,这段字节流才被允许进入Java虚拟机内存的方法区中进行存储。所以后面的三个验证阶段都是基于 方法区的存储结构来进行的。
♣️ 2.2.2 元数据验证
第二阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合《Java语言规范》要求,这个阶段可能包括的验证点如下:
- 这个类是否有父类(除了
java.lang.Object之外,所有的类都应当有父类)。 - 这个类的父类是否继承了不允许被继承的类(被final修饰的类)。
- 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法。
- 类中的字段、方法是否与父类产生矛盾(例如覆盖了父类的final字段,或者出现不符合规则的方法重载,例如方法参数都一致,但是返回值类型却不同等)。
- …
目的:
是对类的元数据信息进行语义校验,保证不存在《Java语言规范》定义相悖的元数据信息。
♣️ 2.2.3 字节码验证
本阶段是真个验证阶段最为复杂的一个阶段,主要目的是通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的。本阶段是对 方法体(Class文件中的Code属性) 进行校验分析,保证被校验类的方法在运行时不会做出未来虚拟机安全的行为。
例如:
- 保证任意时刻操作数栈的数据类型与指令代码序列都能配合工作,例如不会出现类似于“在操作栈放置了一个int类型的数据,使用时却按照long类型来加载本地变量表中” 这样的情况。
- 保证跳转指令都不会跳转到方法体以外的字节码指令上。
- 保证方法体中的类型转换总是有效的,例如可以把一个子类的对象赋值给父类数据类型,这样是安全的,但是把父类对象赋值给自类数据类型,甚至把对象赋值给与它毫无继承关系、完全不想干的一个数据类型,则是危险和不合法的。
如果有一个方法体中的字节码没有通过字节码的验证,那它肯定是有问题的。但是如果通过了验证也不能百分之百的保证他是安全的。
♣️ 2.2.4 符号引用验证
最后一个阶段的校验行为发生在虚拟机将符号转化为直接引用的时候,这个转化动作将在连接的第三阶段( 解析阶段中发生 )。其可以看作是对类自身以为(常量池中各个符号引用)的各类信息进行匹配性校验,通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。本阶段通常需要校验下列内容:
- 符号引用中通过
字符串描述的全限定名是否能找到对应的类。 - 在
指定类中是否存在符合方法的字段描述符及简单名称所描述的方法和字段。 - 符号引用中的类、字段、方法的可访问性(
private、protected、public、<package>) 是否可被当前类访问。 - …
本阶段的主要目的就是确保解析行为能正常执行,如果无法通过 符号引用验证 阶段 Java虚拟机 将会抛出一个 java.lang.IncompatibleClassChangeError 的子类异常,典型的如:java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError 等。
♣️ 2.2.5 总结
验证阶段对于虚拟机的类加载机制来说,是一个非常重要的、但却不是必须要执行的阶段,因为验证阶段只有通过或者不通过的差别,只要通过了验证,其后就对程序运行期没有任何影响,如果程序运行的全部代码(包括自己编写的、第三方包中的、从外部加载的、动态生成的等所有代码)都已经被反复使用和验证过了,再生产环境的实施阶段即可以考虑使用 -X verify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
2.3 准备
准备阶段是正式为类中定义的变量( 静态变量,被 static 修饰的变量 ) 分配内存并设置变量的初始值的阶段。从概念上讲,这些变量所使用的内存都应当在方法区中进行配置,但应该注意方法区本生就是一个逻辑上的区域。在 JDK1.8 之后,类变量会随着 Class 对象一起存放在 Java 堆中。
注意:
准备阶段进行内存分配的仅包括类变量,而不是实例变量,实例变量将会在对象实例化的时候随着对象一起分配在Java堆中。
我们通常情况下数据类型 零值 。
例如:
public static int value = 123;
如上述代码,value 在准备阶段过后的初始值为0而不是123,因为 这时尚未开始执行任何Java方法,而把 value 赋值为123的 putstatic 指令是程序被编译后,存放于类构造器 <clinit>() 方法之中,所以把 value 赋值为123的动作要到类的初始化阶段才会被执行。
零值表补充:
![**[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLQhhdZm-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221218222700941.png)]**](https://img-blog.csdnimg.cn/1a20377ed58a48ba9d5fbc08b9978869.png)
但是会出现特殊情况:
如果类字段的字段属性表中存在 ConstantValue 属性,那在准备阶段变量值就会被初始化为 ConstantValue 属性所指定的初始值,如果上面代码改为以下情况:
public static final int value = 123;
编译时 Javac 会将为 value 值生成 ConstantValue 属性,在准备阶段虚拟机就会根据 ConstantValue 的设置将 value 赋值为 123。
总结:
- 为类变量分配内存并切设置该类变量的默认初始值,即零值。
- 这里不包含使用
final修饰的static,因为final在编译的时候机会分配,准备阶段会显示初始化。 - 这里不会为 实例变量 分配初始化,类变量会分配在方法区中,而实例变量实惠随着对象一起分配到 Java堆中。
2.3 解析
解析过程是 Java虚拟机 将常量池内的 符号引用 替换为 直接引用 的过程。
-
符号引用: 符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。
-
直接引用: 直接引用是可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。
解析的流程有以下四个:
类或接口的解析字段解析方法解析接口方法解析
事实上解析操作都是往往伴随着 JVM 在执行过程中完成初始化之后再执行。
2.4 初始化
类的初始化阶段是类加载过程的最后一个步骤,之前介绍的的几个类的加载动作里,除了在 加载阶段 用户应用程序可以通过自定义类加载器的方式局部参与,其余动作完全由 Java 虚拟机来主导控制权。直到 初始化阶段 ,Java 虚拟机才开始真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。
而在初始化阶段,则会根据程序员通过程序编码指定的主观计划去初始化类变量和其他资源。
总结:
- 初始化阶段就是执行类构造器
<clinit>()方法的过程。 - 此方法不需要被定义,而javac编译器自动收集类中所有变量值的赋值动作和静态代码块中语句合并而来。
- 构造器方法中指令按语句在源文件中出现的顺序执行。
<clinet>()不同于类的构造器(<init>())- 若该类具有父类,
JVM保证子类的<client>()执行前,父类的<clinit>()已经执行完毕。 - 虚拟机必须保证一个类的
<clinit>()方法再多线程下被同步加锁。
3、类加载器
首先我们要知道什么是 类加载器 ?
通过一个类的全限定名来获取描述该类的二进制字节流这个动作放到Java虚拟机外部去实现,以便让应用程序自己去决定如何获取所需的类。实现这个动作的代码被称为类加载器(Class Loader)。
对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在 java 虚拟机中的 唯一性 ,每一个类加载器都拥有一个独立的类名称空间。通俗一点讲就是:比较两个类是否相等,只有在这两个类是同一个类加载器加载的前提下才有意义。
类加载器一共有以下几种:
| 名称 | 加载哪的类 | 说明 |
|---|---|---|
| Bootstrap ClassLoader(启动类加载器) | JAVA_HOME/jre/lib | 无法直接访问 |
| Extension ClassLoader(扩展类加载器) | JAVA_HOME/jre/lib/ext | 上级为 Bootstrap,显示为 null |
| Application ClassLoader(应用程序类加载器) | classpath | 上级为 Extension |
| 自定义类加载器 | 自定义 | 上级为 Application |
类加载器的优先级(由高到低):启动类加载器 -> 扩展类加载器 -> 应用程序类加载器 -> 自定义类加载器 。
3.1 启动类加载器(Bootstrap ClassLoader)
- 这个类加载器是使用
C++/C语言来实现的,嵌套在JVM内部。 - 它用来加载
Java的核心库(JAVA_HOME/jre/lib),用于提供JVM自身需要的类。 - 并不是继承自
java.lang.Class.ClassLoader,没有父加载器。 - 加载扩展类和应用程序类加载器,并指定为他们的父类加载器。
获取启动类能够加载的路径:
public static void main(String[] args) {URL[] urLs = Launcher.getBootstrapClassPath().getURLs();for(URL element: urLs){System.out.println(element.toExternalForm());}}
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/resources.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/rt.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/sunrsasign.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jsse.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jce.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/charsets.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/jfr.jar
file:/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/classes
3.2 扩展类加载器(Extension ClassLoader)
- Java语言编写,由
sun.misc.Launcher$ExtClassLoader实现。 - 派生于ClassLoader类。
- 父类加载器为启动类加载器。
- 从
java.ext.dirs系统属性所指定的目录中加载类库,或从 JDK 的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建JAR在此目录下,则会自由由扩展类加载器加载。
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);
// sun.misc.Launcher$AppClassLoader@18b4aac2
例如:
public static void main(String[] args) {String property = System.getProperty("java.ext.dirs");for(String p: property.split(":")){System.out.println(p);}}
输出:
/Users/tiejiaxiaobao/Library/Java/Extensions
/Users/tiejiaxiaobao/Library/Java/JavaVirtualMachines/liberica-1.8.0_345/jre/lib/ext
/Library/Java/Extensions
/Network/Library/Java/Extensions
/System/Library/Java/Extensions
/usr/lib/java
3.3 应用程序加载器(AppClassLoader)
- 由Java语言编写,由
sun.misc.Launcher$AppClassLoader实现。 - 派生于
ClassLoader类。 - 父类加载器为扩展加载器。
- 它负责加载环境变量
classpath或系统属性java.class.path指定路径下的类库。
3.4 用户自定义类加载器
为什么要自定义类加载器呢?
- 隔离加载类
- 修改类加载的方式
- 扩展加载源
- 防止源码泄露
那又什么时候去定义呢?
- 1)想加载非 classpath 随意路径中的类文件
- 2)都是通过接口来使用实现,希望解耦时,常用在框架设计
- 3)这些类希望予以隔离,不同应用的同名类都可以加载,不冲突,常见于 tomcat 容器
步骤:
- 继承 ClassLoader 父类。
- 要遵从双亲委派机制,重写 findClass 方法 注意不是重写 loadClass 方法,否则不会走双亲委派机制。
- 读取类文件的字节码。
- 调用父类的 defineClass 方法来加载类。
- 使用者调用该类加载器的 loadClass 方法。
4、双亲委派模型
♣️ 什么是双亲委派模型呢?
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UtWnM5dJ-1671638019184)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221219212226647.png)]](https://img-blog.csdnimg.cn/4919cfb7f2d845739d20392b16664369.png)
实现:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {// 首先,检查请求的类是否已经被加载过了 Class c = findLoadedClass(name); if (c == null) {try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name); }} catch (ClassNotFoundException e) {// 如果父类加载器抛出ClassNotFoundException // 说明父类加载器无法完成加载请求}if (c == null) {// 在父类加载器无法加载时// 再调用本身的findClass方法来进行类加载 c = findClass(name);} }if (resolve) { resolveClass(c);}return c;
}
♣️为什么使用双亲委派模型呢?(好处)
- 采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父加载器已经加载了该类时,就没有必要子加载器再加载一次。
- 其次是考虑到安全因素,java 核心 api 中定义类型不会被随意替换,假设通过网络传递一个名为
java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。
参考
本篇笔记参考:尚硅谷JVM 26 - 36 集
《深入理解Java虚拟机》第三版
第六章—类文件结构
第七章—虚拟机类加载机制
文章地址:https://blog.csdn.net/weixin_43591980/article/details/119916684
相关文章:
【学习笔记】深入理解JVM之类加载机制
【学习笔记】深入理解JVM之类加载机制 以后基本上都在语雀上面更新,大家有兴趣可以看看嗷! 首发地址: 知识库 文章流程图: 1、概述 首先我们先来看看一个 Class 文件所需要经过的一个流程图: 而我们今天要重点需讲的…...
驾驭云端之风1——Spring Cloud微服务架构实践指南
本博客纯属个人总结,非原创。喜欢技术交流的,可关注博主,武汉有后端开发群,可支持内推,了解武汉行情等。 前沿 优惠卷平台项目的整体功能和模块,以及每个功能点的技术选型和背后的依据。 搭建一个简化版的…...
【计算机网络基础】
计算机网络基础网络的基本概念网络互联网IP地址MAC地址网络协议网络分层模型网络应用程序的通信流程网络的基本概念 网络 网络是由若干结点和链接这些结点的链路组成,网络中的结点可以是计算机,交换机,路由器等设备 网络设备:交…...
grep与nm命令的应用
相关知识拓展 Linux中grep的命令使用 在Linux中,grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索状态,如果模板搜索成功,则返回0,如果搜索不成功,则返回1,如果搜索的文件不存在&…...
【linux】软硬链接
在linux中在磁盘中定位文件并不是根据文件名而是根据文件的inode,一个文件对应一个inode但是一个inode可以对应多个文件。硬链接硬链接是通过索引节点进行的链接。在Linux中,多个文件指向同一个索引节点是允许的,像这样的链接就是硬链接。硬链…...
骨传导蓝牙耳机排行,盘点几款性能不错的骨传导耳机
随着蓝牙耳机的普及,骨传导耳机也越来越受到欢迎,很多人也都开始在了解并尝试骨传导耳机。相比于其他类型耳机,在舒适度、安全方面有一定优势。尤其是在户外运动时,或者长时间佩戴运动时,使用骨传导耳机可以避免耳朵因…...
ARM中的寄存器
ARM工作模式 ARM有8个基本的工作模式 User 非特权模式,一般在执行上层的应用程序时ARM处于该模式FIQ 当一个高优先级中断产生后ARM将进入这种模式IRQ 当一个低优先级中断产生后ARM将进入这种模式SVC 当复位或执行软中断指令后ARM将进入这种模式Abort 当产生存取异常…...
git操作修改历史版本指定tag标签的代码,并发布新标签
场景: 当项目已经迭代多个版本之后,突然发现旧版本0.0.1出现了紧急bug,需要及时处理; 如果直接用新版本替换上去是存在极大隐患的,且时间来不及; 所以需要直接在0.0.1版本的基础上去修复bug,然…...
SpringMVC——响应处理(1)【包含源码分析】
Controller public class JsonReturnController {ResponseBodyGetMapping("/getPet")public Pet getPet(){Pet petnew Pet();pet.setAge(5);pet.setName("lily");return pet;} }项目启动后 浏览器输入 http://localhost:8080/getPet 。 debug DispatcherS…...
Normalization
1、BN(Batch Normalization) 深度网络参数训练时内部存在协方差偏移(Internal Covariate Shift)现 象:深度网络内部数据分布在训练过程中发生变化的现象。训练深度网络时,神经网络隐层参数更新会导致网络输…...
27K测试老鸟分享自己6年面试心得,四种公司、四种问题…
这里总结了下自己今年的面试情况 先说一下自己的个人情况,普通二本计算机专业毕业,懂python,会写脚本,会selenium,会性能。趁着金三银四跳槽季,面试字节跳动测试岗技术面都已经过了,本来以为是…...
中小企业数字化自动化转型的方法
自动化是我们国内未来的趋势。智能制造的实现主要依托两个基础能力,一个是工业制造技术,另一个就是工业互联网。而自动化是工业制造技术的重要组成部分,是高度智能制造装备的核心部分,与承接着制造单元与工业互联网这两大核心。懂…...
利用GPT-3 Fine-tunes训练专属语言模型
利用GPT-3 Fine-tunes训练专属语言模型 文章目录什么是模型微调(fine-tuning)?为什么需要模型微调?微调 vs 重新训练微调 vs 提示设计训练专属模型数据准备清洗数据构建模型微调模型评估模型部署模型总结什么是模型微调࿰…...
kubeadm方式安装k8s高可用集群(版本1.26x)
K8S官网:https://kubernetes.io/docs/setup/ 高可用Kubernetes集群规划 配置备注系统版本CentOS 7.9Docker版本20.10.xPod网段172.16.0.0/12Service网段10.103.10.0/16 主机IP说明k8s-master01 ~ 03192.168.77.101 ~ 103master节点 * 3k8s-master-lb192.168.77.2…...
分享5款堪称神器的免费软件,建议先收藏再下载
转眼间新年已经过去一个月了,最近陆陆续续收到好多小伙伴的咨询,这边也是抓紧整理出几个好用的软件,希望可以帮到大家。 1.电脑安全管家——火绒 火绒是一款电脑安全软件,病毒库更新及时,界面清晰干净,没…...
【项目实战】从0开始入门JDK源码 - LinkedList源码
一、源码位置 一般来说IDEA配置好JDK以后 ,JDK的源码其实也配置好了,本文是基于JDK1.8的源码说明 rt - java - util - LinkedList 二、 继承关系图 LinkedList public class LinkedList<E>extends AbstractSequentialList<E>implements...
Polygon zkEVM的gas定价
1. 引言 所有的zkEVM都存在一个有趣的问题: 如何给gas定价? 在Ethereum Virtual Machine (EVM)中,gas通过为每个计算设置economic fee,来保持网络安全。恶意行为,如拒绝服务(DoS)攻击&#x…...
stl中的智能指针类详解
C98/03的尝试——std::auto_ptr C11标准废弃了std::auto_ptr(在C17标准中被移除),取而代之的是std::unique_ptr, std::auto_ptr容易让人误用的地…...
Linux 阻塞和非阻塞 IO 实验
目录 一、阻塞和非阻塞简介 1、IO 概念 2、阻塞与非阻塞 二、等待队列 1、等待队列头 2、等待队列项 3、将队列项添加/移除等待队列头 4、等待唤醒 5、等待事件 三、轮询 1、应用程序的非阻塞函数 2、Linux 驱动下的 poll 操作函数 四、阻塞IO之等待事件唤醒 添加…...
你要的react+ts最佳实践指南
本文根据日常开发实践,参考优秀文章、文档,来说说 TypeScript 是如何较优雅的融入 React 项目的。 温馨提示:日常开发中已全面拥抱函数式组件和 React Hooks,class 类组件的写法这里不提及。 前沿 以前有 JSX 语法,…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
MySQL JOIN 表过多的优化思路
当 MySQL 查询涉及大量表 JOIN 时,性能会显著下降。以下是优化思路和简易实现方法: 一、核心优化思路 减少 JOIN 数量 数据冗余:添加必要的冗余字段(如订单表直接存储用户名)合并表:将频繁关联的小表合并成…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
