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

架构师必知的绝活-JVM调优

前言

为什么要学JVM?

首先:面试需要

了解JVM能帮助回答面试中的复杂问题。面试中涉及到的JVM相关问题层出不穷,难道每次面试都靠背几百上千条面试八股?

其次:基础知识决定上层建筑

自己写的代码都不知道是怎么回事,怎么可能写出靠谱的系统?只有理解了JVM的工作机制,才能真正掌握Java这门语言,写出高效、稳定的代码。

然后:学习JVM也是进行JVM调优的基础

写的代码放到线上要如何运行?要配多少内存?4G够不够?线上环境出问题,服务崩溃了,怎么快速定位?怎么解决问题?这些都离不开对JVM的深入理解。

学不学JVM,是能自主解决问题的一流程序员与跟着别人做CRUD的二流程序员的分水岭!

二流程序员会觉得学JVM无关紧要,反正开发也用不上,做开发我只要学各种框架就行了。

而一流程序员都在尽自己能力把JVM每个底层逻辑整理成自己的知识体系,从而在实际工作中游刃有余,解决各种棘手的问题。

插播一条:真的免费,如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题

一、JVM要学什么?

一个Java文件,整体的执行过程整理如下图:


这张图就是整个JVM(JDK1.8)要学的所有东西,其中细节非常多,也很容易让人学得枯燥,但是想要成为高手,就要忍受常人难以忍受的枯燥,不是吗?

下面小北主要带大家以实战的方式整理一下这些核心模块,让大家学的没那么枯燥。

二、Class文件规范

2.1 Class文件结构

首先,从上图可以看到,JVM运行的第一步,是把一个xxxx.java文件编译成为一个class文件,class文件本质上是一个二进制文件。

比如,对于一个ByCodeTest.class文件,使用UltraEdit工具打开,看到的内容部分是这样的:


看到这很多小伙伴内心一万头草泥马就奔腾而出了,这谁看得懂。

别慌,我们可以在IDEA中安装一个ByteCodeView的插件来更直观的查看一个ClassFile的内容,看到的大概内容是下面这样的:

插件安装及使用,这里就不多说了,相信对各位都是小菜一碟


可以看到,一个class文件的大致组成部分。

然后再结合官方的文档,或许能够让你开始对class文件有一个大致的感觉。

​ 例如,前面u4表示四个字节是magic魔数,而这个魔数就是不讲道理的 CAFEBABE 。

​ 而后面的两个u2,表示两个字节的版本号。例如我们用 JDK8 看我们之前的class文件,minor_version就是 00 00,major_version就是 00 34。换成二进制就是 52。52.0 这就是 JVM 给 JDK8 分配的版本号。这两个版本号就表示当前这个class文件是由JDK8编译出来的。后续就只能用8以前版本的JVM执行。这就是JDK版本向前兼容的基础。

例如,如果你尝试用JDK8去引用Spring 6或者SpringBoot 3以后的新版本,就会报错。就是因为Spring 6和SpringBoot 3发布出来的class文件,是用JDK17编译的,版本号是61。JDK8是无法执行的。

2.2 理解字节码指令

在上面的字节码指令中,我们重点需要关注的是方法,也就是我们自己写的代码的部分。

例如在ByteCodeTest中的typeTest()这个方法,在Class文件中是这样记录的:


图中 的每一行就是一个字节码指令。
上述字节码的含义,如果不考虑异常的话,那么JVM虚拟机执行的代码逻辑应该是下面这样的:

do{从程序计数器中读取 PC 寄存器的值 + 1;根据 PC 寄存器指示的位置,从字节码流中读取一个字节的操作码;if(字节码存在操作数) 从字节码流中读取对应字节的操作数;执行操作码所定义的操作;
}while(字节码流长度>0)

这些字节码指令你看不懂?没关系,至少现在,你可以知道你写的代码在 Class 文件当中是怎么记录的了😀

另外,如果你还想更仔细一点的分辨你的每一样代码都对应哪些指令,那么在这个工具中还提供了一个LineNumberTable,会告诉你这些指令与代码的对应关系。

起始 PC 就是这些指令的字节码指令的行数,行号则对应 Java 代码中的行数。
实际上,Java 程序在遇到异常时给出的堆栈信息,就是通过这些数据来反馈报错行数的。

2.3 字节码指令解读

在ByteCodeTest中,我们写了一个typeTest方法:

初学者小白看到这里肯定不禁困惑:这些莫名其妙的true和false是怎么蹦出来的?

如果你之前恰巧刷到过这样的面试题,或许你会记得这是因为JAVA的基础类型装箱机制引起的小误会。

但是你知道产生这个问题的底层原因是什么吗?

首先,我们可以从LineNumberTable 中获取到这几行代码对应的字节码指令:


以前面三行为例,三行代码对应的 PC 指令就是从 0 到 10 号这几条指令。把指令摘抄下来是这样的:

 0 bipush 102 invokestatic #2 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>5 astore_16 bipush 108 invokestatic #2 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
11 astore_2
12 getstatic #3 <java/lang/System.out : Ljava/io/PrintStream;>

可以看到,在执行astore指令往局部变量表中设置值之前,都调用了一次Integer.valueOf方法。

而在这个方法中,对于[-128,127]范围内常用的数字,实际上是构建了缓存的。每次都从缓存中获取一个相同的值,他们的内存地址当然就是相等的了。

这些初学者的梦魇,是不是在这个过程中找到了终极答案?

2.4 字节码指令是如何工作的

要了解字节码指令是如何工作的,就不得不先了解一下JVM中两个重要的数据结构:局部变量表和操作数栈。

在 JVM 虚拟机中,会为每个线程构建一个线程私有的内存区域。

其中包含的最重要的数据就是程序计数器和虚拟机栈。

其中程序计数器主要是记录各个指令的执行进度,用于在 CPU 进行切换时可以还原计算结果。

虚拟机栈中则包含了这个线程运行所需要的重要数据。

虚拟机栈是一个先进后出的栈结构,其中会为线程中每一个方法构建一个栈帧。而栈帧先进后出的特性也就对应了我们程序中每个方法的执行顺序。每个栈帧中包含四个部分:

  • 局部变量表
  • 操作数栈
  • 动态链接库
  • 返回地址。

操作数栈是一个先进后出的栈结构,主要负责存储计算过程中的中间变量。

操作数栈中的每一个元素都可以是包括long型和double在内的任意 Java 数据类型。

局部变量表可以认为是一个数组结构,主要负责存储计算结果。存放方法参数和方法内部定义的局部变量。以 Slot 为最小单位。

动态链接库主要存储一些指向运行时常量池的方法引用。每个栈帧中都会包含一个指向运行时常量池中该栈帧所属方法的应用,持有这个引用是为了支持方法动态调用过程中的动态链接。

返回地址存放调用当前方法的指令地址。一个方法有两种退出方式,一种是正常退出,一种是抛异常退出。如果方法正常退出,这个返回地址就记录下一条指令的地址。如果是抛出异常退出,返回地址就会通过异常表来确定。

附加信息主要存放一些 HotSpot 虚拟机实现时需要填入的一些补充信息。这部分信息不在 JVM 规范要求之内,由各种虚拟机实现自行决定。

其中最为重要的就是操作数栈和局部变量表了

例如,对于初学者最头疼的++操作,下面的 mathTest 方法

public int mathTest(){int i = 1 ;i = i++;return i;}

i 的返回结果是多少?

我们都知道 i 的返回结果是 1 ,但是++自增操作到底有没有执行呢?就可以按照指令这样进行解释:

0 iconst_1   //往操作数栈中压入一个常量1
1 istore_1  // 将 int 类型值从操作数栈中移出到局部变量表1 位置
2 iload_1  // 从局部变量表1 位置装载int 类型的值到操作数栈中
3 iinc 1 by 1  // 将局部变量表 1 位置的数字增加 1
6 istore_1  // 将int类型值从操作数栈中移出到局部变量表1 位置
7 iload_1  // 从局部变量表1 位置装载int 类型的值到操作数栈中
8 ireturn  // 从操作数栈顶,返回 int 类型的值

这个过程中,k++是在局部变量表中对数字进行了自增,此时栈中还是 1。接下来执行=操作,就对应一个istore指令,从栈中将数字装载到局部变量表中。局部变量表中的k的值(对应索引 1 位置),就还是还原成了 1。

那么接下来,你是不是可以自行理解一下 k=++k,是怎么执行的呢?

2.5 补充知识点:大厂面试题

如何确定一个方法需要多大的操作数栈和局部变量?

实际上,每个方法在执行前都需要申请对应的资源,主要是内存。如果内存空间不够,就要在执行前直接抛出异常,而不能等到执行过程中才发现要用的内存空间申请不下来。

有些面试时,是会给你一个具体的方法,让你自己一下计算过程中需要几个操作数栈和几个局部变量。

这是对算法的基础要求。但是在工作中,其实class文件当中就记录了所需要的操作数栈深度和局部变量表的槽位数。

例如对于 mathTest方法,所需的资源在工具中的纪录是这样的:

以后被领导问的时候可以直接通过这种方式告诉他就行了

这里会有一个小问题,如果你自己推演过刚才的计算过程,可以看到,局部变量表中,明明只用到了索引为 1 的一个位置而已,为什么局部变量表的最大槽数是 2 呢?

这是因为对于非静态方法,JVM 默认都会在局部变量表的 0 号索引位置放入this变量,指向对象自身。所以我们可以在代码中用this访问自己的属性。

一个槽可以存放 Java 虚拟机的基本数据类型,对象引用类型和returnAddress类型

插播一条:真的免费,如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题

三、类加载

Class文件中已经定义好了一个Java程序执行的全部过程,接下来就是要扔到JVM中执行。

既然要执行,就少不了类加载的模块。而有趣的是,类加载模块是少数几个可以在Java代码中扩展的JVM底层功能。

类加载模块在JDK8之后,发生了非常重大的变化,本文主要以JDK8为例讲解

3.1 JDK8的类加载体系

有了 Class 文件之后,接下来就需要通过类加载模块将这些 Class 文件加载到 JVM 内存当中,这样才能执行。而关于类加载模块,最为重要的内容有以下三点:

  • 每个类加载器对加载过的类保持一个缓存。
  • 双亲委派机制,即向上委托查找,向下委托加载。
  • 沙箱保护机制。

3.2 双亲委派机制

JDK8中的类加载器都继承于一个统一的抽象类ClassLoader,类加载的核心也在这个父类中。

其中,加载类的核心流程如下:


核心代码如下:

//类加载器的核心方法
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// 每个类加载起对他加载过的类都有一个缓存,先去缓存中查看有没有加载过Class<?> c = findLoadedClass(name);if (c == null) {//没有加载过,就走双亲委派,找父类加载器进行加载。long t0 = System.nanoTime();try {if (parent != null) {c = parent.loadClass(name, false);} else {c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {}if (c == null) {long t1 = System.nanoTime();// 父类加载起没有加载过,就自行解析class文件加载。c = findClass(name);sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}//这一段就是加载过程中的链接Linking部分,分为验证、准备,解析三个部分。// 运行时加载类,默认是无法进行链接步骤的。if (resolve) {resolveClass(c);}return c;}}

这个方法里,就是最为核心的双亲委派机制。

双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载

并且,这个方法是protected声明的,意味着,是可以被子类覆盖的,所以,双亲委派机制也是可以被打破的。
而关于类加载机制的所有有趣的玩法,也都在这个核心方法里。比如class文件加密加载,热加载等。

补充知识点(面试题:Tomcat为什么要打破双亲委派呢?)

3.3 沙箱保护机制

双亲委派机制有一个最大的作用就是要保护JDK内部的核心类不会被应用覆盖。

而为了保护JDK内部的核心类,JAVA在双亲委派的基础上,还加了一层保险。就是ClassLoader中的下面这个方法。

private ProtectionDomain preDefineClass(String name,ProtectionDomain pd){if (!checkName(name))throw new NoClassDefFoundError("IllegalName: " + name);// 不允许加载核心类if ((name != null) && name.startsWith("java.")) {throw new SecurityException("Prohibited package name: " +name.substring(0, name.lastIndexOf('.')));}if (pd == null) {pd = defaultDomain;}if (name != null) checkCerts(name, pd.getCodeSource());return pd;}

这个方法会用在JAVA在内部定义一个类之前。

这种简单粗暴的处理方式,当然是有很多时代的因素。也因此在JDK中,你可以看到很多javax开头的包。这个奇怪的包名也是跟这个沙箱保护机制有关系的。

四、执行引擎

之前已经看到过,在 Class 文件当中,已经明确的定义清楚了程序的完整执行逻辑。

而执行引擎就是将这些字节指令转为机器指令去执行了。

这一块更多的是跟操作系统打交道,对开发工作其实帮助就不是很大了。

所以,如果不是专门研究语言,执行引擎这一块就没有必要研究太深了。我们也直接跳过。

五、GC垃圾回收

执行引擎会将class文件扔到JVM的内存当中运行,在运行过程中,需要不断的在内存当中创建并销毁对象。

在传统C/C++语言中,这些销毁的对象需要手动进行内存回收,防止内存泄漏。而在Java当中,实现了影响深远的GC垃圾回收机制。

GC 垃圾自动回收,这个可以说是 JVM 最为标志性的功能。

不管是做性能调优,还是工作面试,GC 都是 JVM 部分的重中之重。

而对于 JVM 本身,GC 也是不断进行设计以及优化的核心。

几乎 Java 提出的每个版本都对 GC 有或大或小的改动。

这里,我就用目前还是用得做多的 JDK8,带大家快速梳理一下 GC 部分的主线。

插播一条:真的免费,如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题

5.1 垃圾回收器是干什么的?

在了解 JVM之前,给大家推荐一个工具,阿里开源的 Arthas

官网地址:https://arthas.aliyun.com/
这个工具功能非常强大,是对 Java进程进行性能调优的一个非常重要的工具,对于了解 JVM 底层帮助也非常大。

public class GCTest {public static void main(String[] args) throws InterruptedException {List l = new ArrayList<>();for(int i = 0 ; i < 100_0000 ; i ++){l.add(new String("dddddddddddd"));Thread.sleep(100);}}
}

运行后,使用Arthas 的dashboard指令,可以查看到这个 Java 程序的运行情况。

重点关注中间的 Memory 部分,这一部分就是记录的 JVM 的内存使用情况

  • ps_eden_space:伊甸园区
  • ps_survivor_space:幸存区
  • ps_old_gen:老年代
  • nonheap:非堆内存
  • code_cache:热点指令缓存
  • metaspace:元空间
  • compressed_class_space:压缩类空间

而后面的 GC 部分就是垃圾回收的执行情况。我

们就从这些能看到的部分作为入口,来理解一下一个 Java 进程是怎么管理他的内存的。

从 Memory 部分可以看到,一个 Java 进程会将他管理的内存分为heap堆区和nonheap非堆区两个部分。其中非堆区的几个核心部分像code_cache(热点指令缓存),metaspace(元空间),compressed_class_space(压缩类空间)。这一部分就相当于 Java 进程中的地下室,属于不太活跃的部分。

而中间heap堆区就相当于客厅了,属于Java 中最为核心的部分。

而这其中,又大体分为了eden_spacesurvivor_spaceold_gen三个大的部分,这就是 JVM 内存的主体

堆区是JVM用来存放对象的核心内存区域。

它的大小可以通过两个参数来控制:-Xms(初始堆内存大小)和 -Xmx(最大堆内存大小)。

通过这两个参数可以看出,堆内存是可以扩展的。如果初始内存不够用,JVM会自动扩大堆内存。

但是,如果堆内存扩展到了最大值还不够用,就没法继续扩展了,这时候就会抛出OOM(Out of Memory)异常。

在生产环境中,建议把 -Xms 和 -Xmx 设置成一样的大小,这样可以减少内存扩展时的性能消耗。

GC垃圾回收器的任务就是及时回收这些内存空间,让内存可以重复利用,从而提升系统的性能和稳定性。

5.2 分代收集模型

不同GC,对内存的管理和回收的方式都是不同的。但是这其中面试最喜欢问的,就是关于垃圾分代收集模型。

在Memor部分还可以看到多次出现了 ps_ 这样的字样。这其实就代表JDK8默认的垃圾回收器Parallel Scavenge。

其整体的工作机制如下图:

你知道吗?Java做过统计,80%的对象都是“朝生夕死”,换句话说,这些对象创建快,消亡也快。

这些短命的对象被放在一个比较小的内存区域,这块地方叫“年轻代”。

在年轻代,垃圾回收特别频繁,叫做YoungGC。年轻代又被进一步分成三个区域:一个叫eden区,两个叫survivor区。

默认情况下,这三个区域的大小比例是8:1:1。

那剩下的20%长寿对象去哪了?

它们被放到另一块内存区域,这地方叫“老年代”。

老年代的对象竞争没那么激烈,所以垃圾回收的频率也低,只有空间不够用时才进行,叫OldGC。

年轻代和老年代的默认大小比例是1:2。

在常见的分代收集模型中,对象会首先在eden区创建,经过一次YoungGC后,如果对象没有被回收,就会被移动到一个survivor区。

下一次YoungGC时,这些幸存的对象又会被移动到另一个survivor区。每次移动,都会记录一个分代年龄。一直到分代年龄达到阈值(默认是16),这些对象就会被移到老年代。到了老年代后,就不再记录分代年龄了,安安静静地待着,直到“退休”。

这就是JDK最有代表性的分代收集机制。通过这个机制,JVM可以对不同的对象采取不同的回收策略,从而大大提高垃圾回收的效率。

5.3 JVM中有哪些垃圾回收器?

java 从诞生到现在最新的 JDK21 版本,总共就产生了以下十个垃圾回收器


其中,左边的都是分代算法。也就是将内存划分为年轻代和老年代进行管理。

而有虚线的部分表示可以协同进行工作。

JDK8默认就是使用的Parallel Scavenge和Parallel Old的组合。也就是在arthas的dashboard中看到的ps。

右侧的是不分代算法。也就是不再将内存严格划分位年轻代和老年代。

JDK9 开始默认使用 G1。而 ZGC是目前最先进的垃圾回收器。

shennandoah则是OpenJDK 中引入的新一代垃圾回收器,与 ZGC 是竞品关系。Epsilon是一个测试用的垃圾回收器,根本不干活。

六、GC 情况分析实例

GC可以说是决定JAVA程序运行效率的关键。因此我们一定要学会定制GC参数,以及分析GC日志,从而达到调优的目的

6.1 如何定制GC运行参数

现在,不同的GC垃圾回收器适用于不同的场景,所以我们得根据业务场景来定制合理的GC运行参数。

在Java程序运行过程中,会遇到各种问题:

有时CPU飙高
有时FullGC频繁
有时OOM异常等等

这些问题大多需要凭经验深入分析,才能对症下药。

那我们该怎么定制JVM运行参数呢?

首先得知道有哪些参数可以选择。

JVM的参数主要有三类

  • 标准参数:以-开头,所有HotSpot都支持。例如java -version。可以用java -help或java -?查看所有标准参数。

  • 非标准参数:以-X开头,是特定HotSpot版本支持的指令。例如java -Xms200M -Xmx200M。可以用java -X查看所有非标准参数。

  • 不稳定参数:以-XX开头,这些参数与特定HotSpot版本对应,可能换个版本就没有了,文档资料也特别少。以下是JDK8中的几个有用指令:

java -XX:+PrintFlagsFinal:打印所有最终生效的不稳定指令。
java -XX:+PrintFlagsInitial:打印默认的不稳定指令。
java -XX:+PrintCommandLineFlags:打印当前命令的不稳定指令,可以看到使用了哪种GC。JDK1.8默认用的是ParallelGC。

例如下面一个简单的示例代码:

public static void main(String[] args) {ArrayList<byte[]> list = new ArrayList<>();for (int i = 0; i < 500; i++) {byte[] arr = new byte[1024 * 100];//100KBlist.add(arr);try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}

然后在执行这个方法时,添加以下 JVM 参数:

-Xms60m -Xmx60m -XX:SurvivorRatio=8 -XX:+PrintGCDetails


执行后,可以看到下面输出内容

这里面就记录了两次 MinorGC 和两次 FullGC 的执行效果。

当然,目前这些日志信息只是打印在控制台,你只能凭经验自己强行去看。

接下来,就可以添加-Xloggc参数,将日志打印到文件里。然后拿日志文件进行整体分析。

6.3 GC日志分析

这些GC日志隐藏了项目运行非常多隐蔽的问题

要如何发现其中的这些潜在的问题呢?

肉眼去看肯定是不现实的,这时候就要使用工具了。

这里推荐一个开源网站 https://www.gceasy.io/ 这是国外一个开源的GC 日志分析网站。

你可以把 GC 日志文件直接上传到这个网站上,他就会分析出日志文件中的详细情况。

这是个收费网站,但是有免费使用的额度

例如,在我们之前的示例中,添加一个参数 -Xloggc:./gc.log ,就可以将GC日志打印到文件当中。

接下来就可以将日志文件直接上传到这个网站上。网站就会帮我们对GC情况进行分析。示例文件得到的报告是这样的:

通过这份报告,你能迅速识别项目运行中潜藏的问题。报告不仅提供了具体的修改建议,还包含详尽的指标分析。如果你觉得这些建议还不够详细,可以利用这些指标做进一步的分析,找到更多改进的方向。

如果是你们自己开发的项目,那接下来就可以根据这些建议和数据,深入分析,调整参数,优化配置。到了这一步,恭喜你,已经成功入门架构师的核心技能——JVM调优了。

总结

聊到这里,你对JVM是不是有点感觉了?

在这个过程中,你是不是还有很多细节上的疑问?

保持这些疑问,它们会成为你后续深入学习那些晦涩枯燥的底层理论的动力。这不会是一个容易的过程,但正是因为有挑战,才更有价值,不是吗?

踏上这条学习JVM的路,你会发现其中的复杂与精彩。而那些疑问和挑战,正是推动你不断前行的力量。保持好奇心和耐心,你才能一步步掌握这门技术,成为真正的Java架构师!

最后说一句(求关注,求赞,别白嫖我)

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。
这是大佬写的, 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏

点赞对我真的非常重要!在线求赞,加个关注我会非常感激!

真的免费,如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题

相关文章:

架构师必知的绝活-JVM调优

前言 为什么要学JVM&#xff1f; 首先&#xff1a;面试需要 了解JVM能帮助回答面试中的复杂问题。面试中涉及到的JVM相关问题层出不穷&#xff0c;难道每次面试都靠背几百上千条面试八股&#xff1f; 其次&#xff1a;基础知识决定上层建筑 自己写的代码都不知道是怎么回事&a…...

小米平板6系列对比

小米平板6系列目前有4款&#xff0c;分别为6、6 Pro、6 Max、6S Pro。具体对比如下表所示。 小米平板型号66 Pro6 Max6S Pro实物图发布时间2023年4月21日2023年4月21日2023年8月14日2024年2月22 日屏幕大小11英寸11英寸14英寸12.4英寸分辨率2.8K2.8K2.8K3K刷新率144Hz144Hz120…...

用 Rust 实现一个替代 WebSocket 的协议

很久之前我就对websocket颇有微词&#xff0c;它的确满足了很多情境下的需求&#xff0c;但是仍然有不少问题。对我来说&#xff0c;最大的一个问题是websocket的数据是明文传输的&#xff0c;这使得websocket的数据很容易遭到劫持和攻击。同时&#xff0c;WebSocket继承自HTTP…...

【docker】2. 编排容器技术发展史(了解)

该篇文章介绍的主要是编排以及容器技术的发展史(了解即可)&#xff0c;如果想单纯学习docker命令操作可直接略过&#xff01;&#xff01;&#xff01; 容器技术发展史 Jail 时代 容器不是一个新概念或者新技术&#xff0c;很早就有了&#xff0c;只是近几年遇到了云计算&am…...

吉利银河L6(官方小订送的3M) 对比 威固vk70+ks15

吉利送的号称价值2000的3M效果 撕膜重贴 威固vk70ks15 之后的效果 // 忘记测反射的热量了 可以验证金属膜是反射热而不是吸热 金属膜 手机GPS还能用吗 亲测 能用 太阳能总阻隔率 3M貌似20%出头 威固前档55% 侧后挡高一点不超过60% 夏天真实太阳发热能量 即阻隔率55%到60% …...

three.js实现雪花场景效果

点击获取雪花图片素材 提取码:lywa // 雪花效果 import * as THREE from "three" export function getsnowEffect(th) {console.log(th, th) // this 场景var that th// 创建一个BufferGeometry对象&#xff0c;用于存储顶点数据 const geometry new THREE.Buffe…...

鸿蒙 HarmonyOS NEXT星河版APP应用开发-阶段一

一、鸿蒙开发环境搭建 DevEco Studio安装 下载 访问官网&#xff1a;https://developer.huawei.com/consumer/cn/deveco-studio/选择操作系统版本后并注册登录华为账号既可下载安装包 安装 建议&#xff1a;软件和依赖安装目录不要使用中文字符软件安装包下载完成后&#xff0…...

Elasticsearch优化索引映射和设置

在Elasticsearch的世界中&#xff0c;优化索引的映射&#xff08;mapping&#xff09;和设置&#xff08;settings&#xff09;对于提高搜索性能、存储效率和系统稳定性至关重要。本文将带您深入了解如何针对Elasticsearch的索引进行优化&#xff0c;帮助您构建更高效、更可靠的…...

boss直聘招聘数据可视化分析

boss直聘招聘数据可视化分析 一、数据预处理二、数据可视化三、完整代码一、数据预处理 在 上一篇博客中,笔者已经详细介绍了使用selenium爬取南昌市web前端工程师的招聘岗位数据,数据格式如下: 这里主要对薪水列进行处理,为方便处理,将日薪和周薪的数据删除,将带有13薪…...

小程序人脸分析

公司的业务需求是用户在使用某个功能前&#xff0c;必须使用人脸识别&#xff0c;确保当前使用人是用户本人&#xff0c;防止某些功能乱用。后端用的是腾讯的人脸识别方案&#xff0c;这里只是前端的识别代码&#xff0c;保证人脸剧中&#xff0c;大小合适&#xff0c;有一个人…...

UML建模笔记

5个视图 设计。类&#xff0c;接口&#xff0c;对象如何协作。实现。组件&#xff0c;运行程序&#xff0c;文档关系。用例。用户功能期望。进程。并发与同步相关进程&#xff0c;线程。部署。部署到计算机。 建模目的 和客户共创追踪需求变更协同开发进度控制持续迭代测试生…...

初见SpringCloud ing

Consul 服务注册与发现 服务注册与发现 服务注册&#xff1a;微服务在启动时&#xff0c;会将自己的信息&#xff08;如 IP 地址、端口、服务名称等&#xff09;注册到 Consul。 服务发现&#xff1a;其他微服务可以通过 Consul 查询到已注册的服务&#xff0c;并通过这些信息…...

Python | Leetcode Python题解之第198题打家劫舍

题目&#xff1a; 题解&#xff1a; class Solution:def rob(self, nums: List[int]) -> int:if not nums:return 0size len(nums)if size 1:return nums[0]first, second nums[0], max(nums[0], nums[1])for i in range(2, size):first, second second, max(first nu…...

什么是中断?---STM32篇

目录 一&#xff0c;中断的概念 二&#xff0c;中断的意义 三&#xff0c;中断的优先级 四&#xff0c;中断的嵌套 如果一个高优先级的中断发生&#xff0c;它会立即打断当前正在处理的中断&#xff08;如果其优先级较低&#xff09;&#xff0c;并首先处理这个高优…...

51单片机第1步_putchar()和_getkey()应用

没有开发板&#xff0c;没有烧录器&#xff0c;没有学习场所&#xff0c;如何学习写51单片机的程序&#xff1f;除了采用软件模拟仿真&#xff0c;没有更好的方法&#xff0c;因此&#xff0c;使用串口是学习的第一步。 1、_getkey ()函数 在C:\Keil\C51\LIB中有一个叫GETKEY…...

微信小程序中的地图的使用

微信小程序中的地图组件 是一个用于展示地图的组件&#xff0c;提供了丰富的功能和配置选项&#xff0c;可以实现定位、标记、路线规划等多种地图相关的交互。下面是对这个组件的详细介绍&#xff0c;包括属性、事件以及示例代码。 组件属性 基础属性 longitude: 地图中心的经…...

MySQL root密码丢失处理

没有记住MySQL数据库root用户默认密码(为初始化安装mysql时默认生成) 1)修改/etc/my.cnf文件,在[mysqld]的段中加上一句:skip-grant-tables 重启mysql服务 [root@localhost ~]# service mysqld restart 2)以无密码方式进入mysql: [root@localhost ~]# /usr/local/my…...

RabbitMQ中java实现队列和交换机的声明

java实现队列和交换机的声明 在之前我们都是基于RabbitMQ控制台来创建队列、交换机。但是在实际开发时&#xff0c;队列和交换机是程序员定义的&#xff0c;将来项目上线&#xff0c;又要交给运维去创建。那么程序员就需要把程序中运行的所有队列和交换机都写下来&#xff0c;…...

解决SPA(单页应用)首屏加载速度慢

SPA是目前流行的前端开发模式&#xff0c;相对于传统的多页面用户体验更好&#xff0c;操作更顺畅&#xff0c;开发效率也更高。但是SPA首屏加载速度慢一直是个致命的问题&#xff0c;由于SPA应用首次打开需要一次性加载大量的静态资源&#xff0c;这就导致了加载速度慢的问题&…...

ElementUI框架搭建及组件使用

前言: 当开始使用ElementUI框架来搭建网站或Web应用程序时&#xff0c;了解框架的基本结构和组件的使用是至关重要的。ElementUI是一个基于Vue.js的框架&#xff0c;提供了丰富的UI组件和工具&#xff0c;可以帮助开发人员快速构建现代化的用户界面。 在本文中&#xff0c;我…...

同三维T908转换器 SDI转DVI/HDMI/VGA/色差分量/AV转换器

同三维T908转换器 SDI转DVI/HDMI/VGA/色差分量/AV转换器 1路SDI进&#xff0c;1路DVI(可转HDMI/VGA/色差分量/AV)3.5音频1路SDI出,可以支持音频解嵌&#xff0c;也可把3.5音频加嵌转换输出&#xff0c;输出分辨率可调&#xff0c;支持图像翻转180度 一、产品简介 SDI转万能转…...

【设计模式】【创建型5-5】【原型模式】

文章目录 原型模式代码示例 原型模式 代码使用&#xff1a;spring框架里 bean的作用域 用途&#xff0c;以原型为模板&#xff0c;源源不断的创建&#xff08;克隆 clone&#xff09;对象。当直接创建对象的代价比较大时&#xff0c;则采用这种模式。 代码示例 public class…...

原子变量原理剖析

一、原子操作 原子操作保证指令以原子的方式执行&#xff0c;执行过程不被打断。先看一个实例&#xff0c;如下所示&#xff0c;如果thread_func_a和thread_func_b同时运行&#xff0c;执行完成后&#xff0c;i的值是多少&#xff1f; // test.c static int i 0;void thread…...

WebSocket走私实践(附赠LiveGBS监控系统未授权管理员密码重置)

WebSocket走私实践&#xff08;附赠LiveGBS监控系统未授权管理员密码重置&#xff09; 对此&#xff0c;我特别感谢TryHackMe和HackTheBox academy&#xff0c;永远相信和追随英国TryHackMe所教导的网络安全知识,并保持学习 WebSocket走私相关的知识在这里 前段时间学习过htt…...

CentOS 7 和 CentOS Stream 8 的主要区别

更新频率&#xff1a; CentOS 7&#xff1a;传统的稳定版本&#xff0c;主要用于生产环境&#xff0c;更新频率较低&#xff0c;主要包含安全补丁和重要修复。CentOS Stream 8&#xff1a;滚动发布版本&#xff0c;更新更频繁&#xff0c;包含最新的特性和改进。它处于 Fedora …...

基于go1.19的站点模板爬虫

一、go1.19 go1.19是Go语言的一个版本,于2021年8月发布。它带来了许多新的功能和改进,包括但不限于以下方面: 并发性能改进:go1.19引入了新的调度器算法,称为“网状调度器(netlink scheduler)”,它可以更好地处理大量并发任务,在某些情况下提高了系统的并发能力。 垃…...

(单机版)神魔大陆|v0.51.0|冰火荣耀

前言 今天给大家带来一款单机游戏的架设&#xff1a;神魔大陆v0.51.0:冰火荣耀。 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; (单机版)神魔大陆 下面我将详细的教程交给大家&#xff0c;请耐心阅…...

k8s自动补全工具和UI管理界面

分享两个有利于K8S的工具 目录 分享两个有利于K8S的工具 一、部署Dashboard&#xff08;主节点&#xff09; 介绍 1.1、查看集群状态 1.2、下载yaml文件并运行Dashboard 1.3、部署服务 1.4、创建访问账户、获取token&#xff08;令牌&#xff09; 1.5、浏览器访问Dash…...

内网渗透:内网基础信息收集

Windows&#xff1a; whoami:查看当前当前主机名和登录用户名 whoami /user : 打印当前主机名和输出SID ​ SID的最后一个数字&#xff1a; 1000&#xff1a;普通管理员 500&#xff1a;administrator 501&#xff1a;Guest 516&#xff1a;域控 544&#xff1a;域管理员 net…...

cos符号链提示是什么?TOT呢?

**关于cos符号链提示&#xff08;Chain-of-Symbol Prompting, CoS&#xff09;**&#xff1a; Chain-of-Symbol Prompting&#xff08;CoS&#xff09;是用于大型语言模型&#xff08;LLMs&#xff09;的一种新的提示方法。它旨在解决LLMs在空间场景中的理解和规划问题&#xf…...

docker-compose部署Flink及Dinky

docker-compose部署Flink及Dinky 服务器环境&#xff1a;centos7 1. 配置hosts vim /etc/hostsx.x.x.x jobmanager x.x.x.x taskmanager x.x.x.x dinky-mysql2. 文件目录结构 . ├── conf │ ├── JobManager │ │ ├── flink-conf.yaml │ │ ├── log…...

数字时代的文化革命:Facebook的社会影响

随着数字技术的飞速发展和互联网的普及&#xff0c;社交网络如今已成为人们日常生活中不可或缺的一部分。在众多社交平台中&#xff0c;Facebook作为最大的社交网络之一&#xff0c;不仅连接了全球数十亿用户&#xff0c;更深刻影响了人们的社会互动方式、文化认同和信息传播模…...

66.前端接口调用返回400的错误

错误代码400通常表示由于无效的请求导致服务器无法处理请求。这可能是由于以下原因之一&#xff1a; 1.语法错误&#xff1a;客户端发送的请求可能存在语法错误&#xff0c;例如缺少必需的参数、格式不正确等。 2.未授权&#xff1a;如果API需要认证&#xff0c;而客户端没有提…...

Hadoop 安装与伪分布的搭建

目录 1 SSH免密登录 1.1 修改主机名称 1.2 修改hosts文件 1.3 创建hadoop用户 1.4 生成密钥对免密登录 2 搭建hadoop环境与jdk环境 2.1 将下载好的压缩包进行解压 2.2 编写hadoop环境变量脚本文件 2.3 修改hadoop配置文件&#xff0c;指定jdk路径 2.4 查看环境是否搭建完成 3 …...

网络安全:渗透测试思路.(面试)

网络安全&#xff1a;渗透测试思路.&#xff08;面试&#xff09; 渗透测试&#xff0c;也称为 "pen testing"&#xff0c;是一种模拟黑客攻击的网络安全实践&#xff0c;目的是评估计算机系统、网络或Web应用程序的安全性. 目录&#xff1a; 网络安全&#xff1a;…...

优化堆排序

优化堆排序 堆排序是一种基于比较的排序算法,它利用堆这种数据结构来进行排序。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。堆排序算法分为两个大的步骤:首先将待排序的序列构造成一个最大堆,此时,整个序…...

vue3使用一些组件的方法

iconpark...

OceanBase 4.2.1 离线安装

OceanBase 4.2.1 离线安装 4.2 版本的OceanBase支持一键安装&#xff0c;所以在线版本的安装简单了很多&#xff0c;但在无法连接网络的情况下安装就只能手动离线安装。 注&#xff1a;如下安装过程都是在同一台机器上面进行&#xff0c;也就是只有一个节点&#xff0c;多个节…...

ForkJoin

线程数超过CPU核心数是没有任何意义的【因为要使用CPU密集型运算】 Fork/Join&#xff1a;线程池的实现&#xff0c;体现是分治思想&#xff0c;适用于能够进行任务拆分的 CPU 密集型运算&#xff0c;用于并行计算 任务拆分&#xff1a;将一个大任务拆分为算法上相同的小任务…...

实验2 色彩模式转换

1. 实验目的 ①了解常用的色彩模式&#xff0c;理解色彩模式转换原理&#xff1b; ②掌握Photoshop中常用的颜色管理工具和色彩模式转换方法&#xff1b; ③掌握使用Matlab/PythonOpenCV编程实现色彩模式转换的方法。 2. 实验内容 ①使用Photoshop中的颜色管理工具&#xff…...

AES加密算法及AES-CMAC原理白话版系统解析

本文框架 前言1. AES加密理论1.1 不同AES算法区别1.2 加密过程介绍1.2.1 加密模式和填充方案选择1.2.2 密钥扩展1.2.3分组处理1.2.4多轮加密1.2.4.1字节替换1.2.4.2行移位1.2.4.3列混淆1.2.4.4轮密钥加1.3 加密模式1.3.1ECB模式1.3.2CBC模式1.3.3CTR模式1.3.4CFB模式1.3.5 OFB模…...

24年hvv前夕,微步也要收费了,情报共享会在今年结束么?

一个人走的很快&#xff0c;但一群人才能走的更远。吉祥同学学安全https://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247483727&idx1&sndb05d8c1115a4539716eddd9fde4e5c9&scene21#wechat_redirect这个星球&#x1f517;里面已经沉淀了&#xff1a; 《Ja…...

【地理库 Turf.js】

非常全面的地理库 &#xff0c; 这里枚举一些比较常用&#xff0c;重点的功能&#xff0c; 重点功能 提供地理相关的类&#xff1a;包括点&#xff0c;线&#xff0c;面等类。 测量功能&#xff1a;点到线段的距离&#xff0c;点和线的关系等。 判断功能&#xff1a; 点是否在…...

springboot在线考试 LW +PPT+源码+讲解

第三章 系统分析 3.1 可行性分析 一个完整的系统&#xff0c;可行性分析是必须要有的&#xff0c;因为他关系到系统生存问题&#xff0c;对开发的意义进行分析&#xff0c;能否通过本系统来补充线下在线考试管理模式中的缺限&#xff0c;去解决其中的不足等&#xff0c;通过对…...

JDBC中的事务及其ACID特性

在JDBC&#xff08;Java Database Connectivity&#xff09;中&#xff0c;事务&#xff08;Transaction&#xff09;是指作为单个逻辑工作单元执行的一系列操作。这些操作要么全部执行&#xff0c;要么全部不执行&#xff0c;从而确保数据库的完整性和一致性。事务是现代数据库…...

Python | Leetcode Python题解之第204题计数质数

题目&#xff1a; 题解&#xff1a; MX5000000 is_prime [1] * MX is_prime[0]is_prime[1]0 for i in range(2, MX):if is_prime[i]:for j in range(i * i, MX, i):#循环每次增加iis_prime[j] 0 class Solution:def countPrimes(self, n: int) -> int:return sum(is_prim…...

【课程总结】Day10:卷积网络的基本组件

前言 由于接下来的课程内容将围绕计算机视觉展开&#xff0c;其中接触最多的内容是卷积、卷积神经网络等…因此&#xff0c;本篇内容将从卷积入手&#xff0c;梳理理解&#xff1a;卷积的意义、卷积在图像处理中的作用以及卷积神经网络的概念&#xff0c;最后利用pytorch搭建一…...

ModuleNotFoundError: No module named ‘_sysconfigdata_x86_64_conda_linux_gnu‘

ModuleNotFoundError: No module named _sysconfigdata_x86_64_conda_linux_gnu 1.软件环境⚙️2.问题描述&#x1f50d;3.解决方法&#x1f421;4.结果预览&#x1f914; 1.软件环境⚙️ Ubuntu 20.04 Python 3.7.0 2.问题描述&#x1f50d; 今天发现更新conda之后&#xff0…...

【物联网】室内定位技术及定位方式简介

目录 一、概述 二、常用的室内定位技术 2.1 WIFI技术 2.2 UWB超宽带 2.3 蓝牙BLE 2.4 ZigBee技术 2.5 RFID技术 三、常用的室内定位方式 3.1 信号到达时间 3.2 信号到达时间差 3.3 信号到达角 3.4 接收信号强度 一、概述 GPS是目前应用最广泛的定位技术&#xff0…...

Leetcode[反转链表]

LCR 024. 反转链表 给定单链表的头节点 head &#xff0c;请反转链表&#xff0c;并返回反转后的链表的头节点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示…...

为什么要在成像应用中使用图像采集卡?

达到最大产量是工业和工厂自动化的关键标准之一。提高传感器分辨率和帧速率有助于实现这一目标&#xff0c;但也使带宽达到极限&#xff0c;并提出了新的传输问题。当前高带宽接口(如10GigE、相机直接与PC连接和嵌入式系统)的实现促使成像应用的许多用户询问如何以最佳配置最优…...

JAVA内存模型(JMM)

Java内存模型&#xff08;Java Memory Model&#xff0c;JMM&#xff09;规定了Java虚拟机如何在多线程环境中对内存的操作进行规范&#xff0c;以确保程序执行的正确性。JMM定义了多线程程序中变量&#xff08;包括实例字段、静态字段和数组元素&#xff09;的访问方式。JMM的…...

Python学习笔记29:进阶篇(十八)常见标准库使用之质量控制中的数据清洗

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…...

数据结构 —— 最小生成树

数据结构 —— 最小生成树 什么是最小生成树Kruskal算法Prim算法 今天我们来看一下最小生成树&#xff1a; 我们之前学习的遍历算法并没有考虑权值&#xff0c;仅仅就是遍历结点&#xff1a; 今天的最小生成树要满足几个条件&#xff1a; 考虑权值所有结点联通权值之和最小无环…...

【MindSpore学习打卡】应用实践-计算机视觉-深入解析 Vision Transformer(ViT):从原理到实践

在近年来的深度学习领域&#xff0c;Transformer模型凭借其在自然语言处理&#xff08;NLP&#xff09;中的卓越表现&#xff0c;迅速成为研究热点。尤其是基于自注意力&#xff08;Self-Attention&#xff09;机制的模型&#xff0c;更是推动了NLP的飞速发展。然而&#xff0c…...

java 利用 gdal 生成遥感tif的缩略图

简要说明 在java&#xff0c;简单使用gdal生成tif文件的缩略图 maven依赖 <!--需要安装完gdal后&#xff0c;本地install gdal包才能使用 --><!--gdal安装可参考 https://blog.csdn.net/qq_41613913/article/details/135743562 --><dependency><groupI…...

ABB 控制柜

1&#xff0c;主计算机&#xff1a;相当于电脑的主机&#xff0c;用于存放系统和数据&#xff0c;需要24V直流电才能工作。执行用户编写的程序&#xff0c;控制机器人进行响应的动作。主计算机有很多接口&#xff0c;比如与编程PC连接的服务网口、用于连接示教器的网口、连接轴…...

MFC CList<CRect, CRect> m_listRect;的用法

CList<CRect, CRect&> 是 MFC&#xff08;Microsoft Foundation Classes&#xff09;中定义的一个双向链表模板类&#xff0c;用于存储 CRect 对象。在使用 CList 时&#xff0c;你可以执行多种操作&#xff0c;比如添加、移除、查找和遍历元素。以下是一些常见的用法…...

微前端(无界)入门

主应用通过props给子应用传值 父子应用通过eventBus通信 通过路由同步实现记录子应用的路由状态 主应用 main.ts: import ./assets/main.cssimport { createApp } from vue import { createPinia } from pinia import WujieVue from wujie-vue3import App from ./App.vue impo…...

Hotcoin Research | 市场洞察:2024年5月13日-5月19日

加密货币市场表现 目前&#xff0c;加密货币总市值为1.32万亿&#xff0c;BTC占比54.41%。 本周行情呈现震荡上行的态势&#xff0c;BTC在5月15日-16日&#xff0c;有一波大的拉升&#xff0c;周末为震荡行情。BTC现价为67125美元。 上涨的主要原因&#xff1a;美国4月CPI为3…...

Hexo最新实战:(一)Hexo7.0+GitHub Pages博客搭建

前言 很多平台都能写博客还有创作激励&#xff0c;为什么我又要搭一个&#xff1f;为什么这次要选择用Hexo框架&#xff1f; 对应的原因是流量自由和省钱&#xff0c;第一个&#xff0c;很多平台能写但不是都有收益&#xff0c;而且平台有自身的规则&#xff0c;比如会屏蔽一…...

d20(184-190)-勇敢开始Java,咖啡拯救人生

目录 网络通信 网络通信三要素&#xff08;IP地址&#xff0c;端口号&#xff0c;协议 IP地址 InetAddress 端口号 协议 传输层的两个通信协议 UDP通信 java.net.Datagramsocket类 客户端 服务端 UDP通信多收多发 客户端 服务端 TCP通信 java.net.Socket类 客…...