科普文:一文搞懂jvm原理(三)执行引擎

概叙

科普文:一文搞懂jvm(一)jvm概叙-CSDN博客

科普文:一文搞懂jvm原理(二)类加载器-CSDN博客

         前面我们介绍了jvm,jvm主要包括两个子系统和两个组件: Class loader(类装载器) 子系统,Execution engine(执行引擎) 子系统;Runtime data area (运行时数据区域)组件, Native interface(本地接口)组件。

        这里我们主要讲解Execution engine(执行引擎),讲到这个就和jvm优化相关。

        图一:jvm的运行时区、执行引擎、本地方法接口和库

        图二:这个是前面文中多次出现的jvm详细图,

        执行引擎是Java虚拟机核心的组成部分之一,属于JVM的下层。

        其中包括 解释器、及时编译器、垃圾回收器。

        “虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。

        JVM的主要任务是负责装载字节码到其内部,但字节码并不能够直接运行在操作系统之上,因为字节码指令并非等价于本地机器指令,它内部包含的仅仅只是一些能够被JVM所识别的字节码指令、符号表,以及其他辅助信息。

        那么,如果想要让一个Java程序运行起来,执行引擎(Execution Engine)的任务就是将字节码指令解释/编译为对应平台上的本地机器指令才可以。

        简单来说,JVM中的执行引擎充当了将高级语言翻译为机器语言的译者。

  • 为什么说Java是半编译半解释性语言?

            JDK 1.0 时代,将 Java 语言定位为“解释执行”还是比较准确的,再后来, Java 也发展出可以直接生成本地代码的编译器。

            现在 JVM 在执行 Java 代码的时候,通常都会将解释执行和编译执行二者结合起来进行。

    • HotSpot采用的是解释执行与即时编译器并存的架构。在Java虚拟机运行时,解释器和即时编译器能互相协作,尽量选择最适合的方式来权衡编译本地代码的时间和解释执行代码的时间。
    • 也可以使用参数设置只使用解释器或者编译器启动。

Java 代码编译和执行过程

        大部分的程序代码转换成物理机的目标代码或虚拟机能执行的指令集之前,都需要经过下图中的各个步骤:

  • 橙色部分是生成字节码文件的过程,和JVM无关
  • 蓝色和绿色才是JVM需要考虑的过程

        Java 代码编译是由 Java 源码编译器来完成,流程图如下所示:

        Java 字节码的执行是由 JVM 执行引擎来完成,流程图如下所示:

jvm执行引擎Execution engine

        JVM中的执行引擎是JVM的重要组成部分之一,主要负责将字节码指令翻译成机器码指令。        

执行引擎的组成

        执行引擎由三个组件组成:

  1. 解释器(Interpreter):就是运行时的“翻译者”,将字节码解释为机器指令。
  2. 及时编译器(JIT:Just In Time Compiler):但是某些频繁执行的热点代码依然采用解释执行的话会导致程序执行很慢,JIT编译器则是负责将热点代码编译分层优化成本地机器码。
  3. 垃圾回收器(Garbager Collection):负责无用对象的销毁,释放内存空间。

1.解释器(Interpreter)

        解释器就是一个运行时的“翻译者”,将字节码指令翻译为对应平台的本地机器指令由CPU执行,当一条指令执行完成后再根据PC寄存器中记录的下一条指令执行解释操作。

        JVM设计者们的初衷仅仅只是单纯地为了满足Java程序实现跨平台特性,因此避免采用静态编译的方式直接生成本地机器指令,从而诞生了解释器:在Java虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。

        当一条字节码指令被解释执行完成后,接着再根据PC寄存器中记录的下一条需要被执行的字节码指令执行解释操作。

        在 Java 的发展历史里,一共有两套解释执行器,即古老的字节码解释器、现在普遍使用的模板解释器。

        字节码解释器在执行时通过纯软件代码模拟字节码的执行,效率非常低下。而模版解释器将每一条字节码和一个模板函数相关联,模板函数中直接产生这条字节码执行时的机器码,从而很大程度上提高了解释器的性能。在 HotSpot VM 中,解释器主要由 Interpreter 模块和 Code 模块组成。

  • Interpreter 模块:实现了解释器的核心功能
  • Code 模块 : 用于管理 HotSpot VM 在运行时生成的本地机器指令。

        由于解释器在设计和实现上非常简单,因此除了 Java 语言之外,还有许多高级语言同样也是基于解释器执行的,比如 python 、Perl 、Ruby 等。但是在今天,基于解释器执行已经沦落为低效的代名词,并且时常被一些 C /C++ 程序员所调侃。

        为了解决这个问题, JVM 平台支持一种叫做即时编译的技术。即时编译的目的是避免函数被解释执行,而是将整个函数体编译成为机器码,每次函数执行时,只执行编译后的机器码即可,这种方式可以时执行效率大幅度提升。

        不过无论如何,基于解释器的执行模式仍然为中间语言的发展做出了不可磨灭的贡献。


2.及时编译器(JIT:Just In Time Compiler)

        当执行某些频繁被调用的代码(比如for循环中的代码)时,如果按照解释执行,效率非常低,这种被频繁调用的代码成为热点代码。为了提高热点代码的执行效率,在运行时,JIT编译器则会将这些代码编译成与本地平台有关的机器码,并进行各种层次的优化。

        及时编译器(Just In Time Compiler),就是虚拟机将源代码直接编译成和本地机器平台相关的机器语言。

        由于解释器在设计和实现上非常简单,因此除了Java语言之外,还有许多高级语言同样也是基于解释器执行的,比如Python、 Perl、Ruby等。但是在今天,基于解释器执行已经沦落为低效的代名词,并且时常被一些C/C+ +程序员所调侃。

        JIT的构成组件包括:

  1. 中间代码生成器——生成中间代码
  2. 代码优化器——优化中间代码
  3. 目标代码生成器——生成机器码或本地代码
  4. 分析器——负责查找热点代码

        HotSpot VM 是目前市面上高性能虚拟机的代表作之一。它采用解释器与及时编辑器并行的结构。在 Java 虚拟机运行时,解释器和即时编译器能够相互协作,各自取长补短,尽力去选择最合适的方式来权衡编译本地代码的时间和直接解释执行代码的时间。

        在今天, Java 程序的运行性能早已脱胎换骨,已经达到了可以和 C/C++ 程序一较高下的地步。

        有些开发人员会感觉到诧异,既然 HotSpot VM 中已经内置了 JIT 编译器了,那么为什么还使用解释器来“拖累”程序的执行性能呢? 比如 JRockit VM 内部就不包含解释器,字节码全部都依靠即时编译器编译后执行。

        首先明确:当程序启动后,解释器可以马上发挥作用,省去编译的时间,立即执行。编译器要想发挥作用,把代码编译成本地代码,需要一定的执行时间。但编译为本地代码后,执行效率高。所以:尽管 JRockit VM中程序的执行性能会非常的高效,但程序在启动时必然会花费更长的时间来进行编译。对于服务器来说,启动时间并非时关注重点,但对于那些看中启动时间的应用场景而言,或许就需要采用解释器与及时编译器并存的架构来换取一个平衡点。在此模式下,当 Java 虚拟机启动时,解释器可以首先发挥作用,而不必等待即时编译器全部编译完成后在执行,这样可以省去许多不必要的编译时间。随着时间的推移,编译器发挥作用,把越来越多的代码编译成本地代码,获得更高的执行效率。

        同时,解释执行在编译器进行激进优化不成立的时候,作为编译器的“逃生门”。

概念解释:

        Java 语言的“编译期”其实是一段 “不确定”的操作过程,因为他可能是指一个前端编译器(其实叫 “编译器的前端” 更准确一些)把 .java 文件转变成 .class 文件的过程;

        也可能是指虚拟机的后端运行期编译器( JIT 编译器, Just In Time Compiler )把字节码转变成机器码的一个过程。

        还可能是指使用静态提前编译器 ( AOT 编译器, Ahead Of Time Compiler ) 直接把 .java 文件编译成本地机器代码的过程。

JIT及时编译器分类

        在Hotspot虚拟机中内置了两种JIT编译器:

        C1编译器:主要关注点在于局部性能优化,适用于执行时间短或对启动性能有要求的程序,如:GUI应用,C1编译器也被称为Client Compiler

        C2编译器:为长期运行的服务端应用程序做性能优化的编译器,适用于执行时间较长或对峰值性能有要求的程序,C2编译器也被称为Server Compiler。

Graal编译器:用Java实现的JIT编译器,JDK10中引入(具体信息参考:https://openjdk.org/jeps/317),JDK17中移除(移除原因参考:https://openjdk.org/jeps/410
        JIT的编译器还分为了两种,分别是C1和C2,在HotSpot VM中内嵌有两个JIT编译器,分别为Client Compiler和Server Compiler。但大多数情况下我们简称为C1编译器 和 C2编译器。开发人员可以通过如下命令显式指定Java虚拟机在运行时到底使用哪一种即时编译器。

  •         client:指定Java虚拟机运行在Client模式下,并使用C1编译器;C1编译器会对字节码进行简单和可靠的优化,耗时短。以达到更快的编译速度。
  •         server:指定Java虚拟机运行在server模式下,并使用C2编译器;C2进行耗时较长的优化,以及激进优化。但优化的代码执行效率更高。

        在不同的编译器上有不同的优化策略,C1编译器上主要有方法内联,去虚拟化、冗余消除:

  •         方法内联:将引用的函数代码编译到引用点处,这样可以减少栈帧的生成,减少参数传递以及跳转过程;
  •         去虚拟化:对唯一的实现樊进行内联;
  •         冗余消除:在运行期间把一些不会执行的代码折叠掉;

        

        C2的优化主要是在全局层面,逃逸分析是优化的基础。基于逃逸分析在C2上有如下几种优化:

  • 标量替换:用标量值代替聚合对象的属性值;
  • 栈上分配:对于未逃逸的对象分配对象在栈而不是堆;
  • 同步消除:清除同步操作,通常指synchronized;


        在Java7版本之后,一旦开发人员在程序中显式指定命令“-server"时,默认将会开启分层编译策略,由C1编译器和C2编译器相互协作共同来执行编译任务。

        总的来说,C2编译器启动时长比C1慢,系统稳定执行以后,C2编译器执行速度远快于C1编译器。

分层编译

        在Java7引入了分层编译,这种方式综合了C1的启动优势和C2的峰值性能优势。分层编译将JVM的执行状态分为5个层次:

        第0层:程序解释执行,默认开启性能监控(Profiling),如果不开启,可触发第二层编译

        第1层:C1编译,将字节码编译成本地代码,进行简单可靠的优化,不开启Profiling

        第2层:C1编译,开启Profiling,仅执行带方法调用次数和循环回边执行次数Profiling的C1编译

        第3层:C1编译,执行所有带Profiling的C1编译

        第4层:C2编译,将字节码编译为本地代码,但会启用一下编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

        Java8中默认开启分层编译,-XX:-TieredCompilation 参数可关闭分层编译只使用C2编译,如果只使用C1编译可设置参数 -XX:TieredStopAtLevel=1

        -Xint参数可设置为强制解释器模式运行,-Xcomp可设置为强制运行JIT编译模式。

热点探测技术

        关于编译器可大致分为两种:

  • 前端编译器:把 .java 文件转变成 .class 文件;
  • 后端编译器:把 .class 文件转变为 机器指令;


        是否需要启动即时编译器将字节码转换为机器指令,则需要根据代码的调用频率而定。一个被多次调用的方法,或者是一个方法体内部循环次数较多的循环体都可以被称之为“热点代码”,即时编译器在运行时会针对那些被频繁调用的热点代码做出深度优化,将其直接编译为本地的机器指令,以此来提升程序的性能。由于这种编译方式发生在方法的执行过程中,因此被称之为栈上替换,或简称为OSR(On Stack Replacement)编译。

        一个方法究竟要被调用多少次,或者一个循环体究竟需要执行多少次循环才可以达到这个标准?必然需要一个明确的阈值,JIT编译器才会将这些“热点代码”编译为本地机器指令执行。这里主要依靠热点探测功能。

        目前HotSpot VM所采用的热点探测方式是基于计数器的热点探测,HotSpot 将会为每一个方法都建立2个不同类型的计数器,分别为方法调用计数器和回边计数器。

  • 方法调用计数器用于统计方法的调用次数;
  • 回边计数器则用于统计循环体执行的循环次数;

方法调用计数器


        这个计数器就用于统计方法被调用的次数,它的默认阈值在Client模式下是1500次,在Server模式下是10000次,超过这个阈值,就会触发即时编译。这个阈值可以通过虚拟机参数 -XX:CompileThreshold 来设定。

        当某个方法调用次数达到阈值就会触发JIT编译优化,jinfo -flag CompileThreshold <pid> 或者 java -XX:+PrintFlagsFinal -version 命令可查看方法调用次数阈值

        当一个方法被调用时,会先检查该方法是否存在被即时编译器编译过的版本,如果存在,则优先使用编译后的本地代码来执行。
        如果不存在已被编译过的版本,则将此方法的调用计数器值加1,然后判断方法调用计数器与回边计数器值之和是否超过方法调用计数器的阀值。如果已超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求;否则就通过解释器执行。

回边计数器


        它的作用是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge)。
        跟方法调用计数器搭配使用,如何两者相加总和超过计数器的阀值,那么就会除法即时编译器。显然,建立回边计数器统计的目的就是为了触发栈上替换编译。

        用于统计方法体中循环体代码执行次数,字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge),用于计算是否为热点代码的阈值。

        计算公式如下:

        回边计数器阈值 = 方法调用计数器阈值(CompileThreshold)*(OSR比率(OnStackReplacePercentage)-解释器监控比例(InterpreterProfilePercentage))/ 100

java -XX:+PrintFlagsFinal -version 命令可查看相关参数

        根据图中显示的各参数的默认值可以计算出回边计数器阈值为:1000 * (140 - 33) = 10700

热点衰减


        如果不做任何设置,方法调用计数器统计的并不是方法被调用的绝对次数,而是一个相对的执行频率,可理解为一段时间之内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让它提交给即时编译器编译,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器热度的衰减,而这段时间就称为此方法统计的半衰周期。可以使用-XX:CounterHalfLifeTime参数设置半衰周期的时间,单位是秒。

        进行热度衰减的动作是在虚拟机进行垃圾收集时顺便进行的,可以使用虚拟机参数 -XX:-UseCounterDecay 来关闭热度衰减,让方法计数器统计方法调用的绝对次数。这样,只要系统运行时间足够长,绝大部分方法都会被编译成本地代码。

如何选择编译器和解释器:

        当然是否需要启动 JIT 编译器将字节码直接译为对应平台的本地机器指令,则需要根据代码被调用执行的频率而定。关于那些需要被编译为本地代码的字节码,也被称之为 “热点代码” JIT 编译器在运行时会针对那些频繁被调用的“热点代码”做出深度优化,将其直接编译为对应平台的本地机器指令,以此提升 Java 程序的性能。

        缺省情况下 HotSpot VM 是采用解释器与即时编译器并存的架构,当然开发人员可以根据具体的应用场景,通过命令显示地为 Java 虚拟机指定在运行时到底是完全采用解释器执行,还是完全采用即时编译器执行。如下所示:

  • -Xint : 完全采用解释器模式执行程序;
  • -Xcomp : 完全采用编译器模式执行程序。如果即时编译出现问题,解释器会介入执行。
  • -Xmixed :采用解释器+即时编译器的混合模式共同执行程序。

静态提前编译器


        JDK9 引入了静态提前编译器(Ahead of Time Compiler)。Java 9引入了实验性AOT编译工具AOTC。它借助了Graal编译器,将所输入的Java类文件转换为机器码,并存放至生成的动态共享库之中。

        静态提前编译器:,是直接把.java文件编译成机器指令。大致过程:.java -> .class -> (使用jaotc) -> .so。

        所谓AOT编译,是与即时编译相对立的一个概念。即时编译指的是在程序的运行过程中,将字节码转换为可在硬件上直接运行的机器码,并部署至托管环境中的过程。而AOT编译指的则是,在程序运行之前,便将字节码转换为机器码的过程。

优点:

  •         Java虚拟机加载已经预编译成二进制库,可以直接执行。不必等待及时编译器的预热,减少Java应用给人带来“第一次运行慢” 的不良体验;

缺点:

  •         破坏了 java “ 一次编译,到处运行”,必须为每个不同的硬件,OS编译对应的发行包;
  •         降低了Java链接过程的动态性,加载的代码在编译器就必须全部已知;
  •         还需要继续优化中,最初只支持Linux X64 java base;


Graal编译器


        自JDK10起,HotSpot又加入了一个全新的及时编译器:Graal编译器,编译效果短短几年时间就追评了G2编译器,未来可期。

特点:

        高效能运行 Java: 使用 GraalVM 执行 Java 程序可以变得更快;
        多语言并行:可以在 Java 里面同时使用多种语言,像是 JavaScript等;
        快速启动:直接把 Java 应用编译成机器码,执行起来体积更小、启动速度更快;

编译优化技术

1. 方法内联

        方法内联的优化行为是将目标方法的代码复制到发起调用的方法中,避免真实方法调用。

    private int add(int a, int b, int c, int d) {return addInt1(a, b) + addInt2(c, d);}
​private int addInt1(int a, int b) {return a + b;}
​private int addInt2(int a, int b) {return a + b;}

        例如上面的代码如果被检测为热点代码,则会被优化为以下代码:

    private int add(int a, int b, int c, int d) {return a + b + c + d;}

        热点方法不一定都会被内联优化,只有当方法体大小小于参数 -XX:FreqInlineSize 值(默认325字节)才会进行内联,非热点方法当方法体小于参数 -XX:MaxInlineSize 值(默认35字节)才会进行内联。

  • 相关性能调优        
    • 减小热点方法检测阈值,增加内联方法体阈值,缺点则是会增加内存占用
    • 尽量避免在一个方法体内写入大量代码,习惯使用小方法体
    • 尽量使用final private static 关键字修饰方法,代码优化时,因为继承需要额外的类型检查。
2. 锁消除

        当方法中的局部方法中创建的对象只能被当前线程访问时,不存在锁竞争,JIT编译会对这个对象的方法进行锁消除。

        参数 -XX:+EliminateLocks 可以开启锁消除(默认开启),-XX:-EliminateLocks 则是关闭锁消除

3. 锁粗化

        如果检测到同一个对象执行了连续的加锁和解锁操作,则会将这一系列操作合并成一个更大的锁,从而提升程序运行效率。

4. 逃逸分析

        JIT编译器会对热点代码中的对象进行逃逸分析,分析该对象动态作用域,当被传递到其他方法中称为方法逃逸,当能被外部方法所引用则为线程逃逸。

        不逃逸到方法逃逸再到线程逃逸,逃逸程度由低到高。

        逃逸分析可以通过参数 -XX:+DoEscapeAnalysis开启(jdk1.8默认开启),或 -XX:-DoEscapeAnalysis 关闭。

        关闭逃逸分析会导致对象分配到堆中,频繁触发垃圾回收导致代码运行慢。

5. 标量替换

        当确定对象不会逃逸出线程之外,该对象则会被分配到栈上,对象分配到栈需要进行成员变量拆分,这种优化技术叫做标量替换。标量替换需要开启逃逸分析。

        标量替换可以通过参数 -XX:+EliminateAllocations开启(jdk1.8默认开启),或-XX:+EliminateAllocations关闭

3.垃圾回收器(Garbager Collection)

        程序计数器、虚拟机栈、本地方法栈随线程而生,也随线程而灭;栈帧随着方法的开始而入栈,随着方法的结束而出栈。这几个区域的内存分配和回收都具有确定性,在这几个区域内不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收了。

        垃圾收集器(Garbage Collection,简称:GC), GC主要用于Java堆的管理。Java 中的堆是 JVM 所管理的最大的一块内存空间,主要用于存放各种类的实例对象。
在系统运行期间,会产生大量的对象实例,对于一些对象实例用完后已经没有引用指向(对象已无法访问),这些对象属于内存垃圾,为了能够回收没用的对象,就诞生了垃圾回收器。

        既然JVM种有垃圾收集器,为什么我们还要去了解垃圾收集和内存分配呢?
答案很简单:当需要排查各种内存溢出,内存泄露问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们必须对这些进行监控和调节。

        关于垃圾回收器,在讲完“jvm运行时区”后,再单独详细描述。

判断对象是否存活


引用计数法


        实现原理:为每个对象头维护一个独立的 counter 计数器,当对象被引用时加1,取消引用时减1。当计数器为 0 时,对象就是不可能再被使用的。
引用计数法虽然会占用一些额外的内存空间来计数,但它的实现原理简单,效率也很高,Java虚拟没有选用计数算法来管理内存,主要原因是引用计数算法存在对象之间循环引用的问题。

下图就是循环引用的例子


可达性分析法
        Java使用的是可达性分析算法来判断对象是否可以被回收。可达性分析将对象分为两类:垃圾回收的根对象(GC Roots)和普通对象,对象与对象之间存在引用关系。
        实现原理:下图中A到B再到C和D,形成了一个引用链,可达性分析算法指的是如果从某个对象到GC Roots对象是可达的,对象就不可被回收。如果某个对象到GC Roots间没有任何引用链相连,那么就可以判定对象是不再使用。


固定可作为GC Roots对象包括以下几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用对象,比如方法中使用到的参数、局部变量、临时变量等。
  2. 方法区中静态属性、常量引用的对象。
  3. 本地方法(Native 方法)栈引用的对象。
  4. Java虚拟机内部引用的对象,如基本数据类型对应的Clas对象。
  5. 所有被同步锁(Synhronized关键字)持有的对象。
  6. 当前活动线程正在运行的线程对象。

等等…
        GC Roots 并不包括堆中对象所引用的对象,这样就不会有循环引用的问题。

常见的几种对象引用


        可达性算法中描述的对象引用,一般指的是强引用,即是GCRoot对象对普通对象有引用关系,只要这层关系存在,普通对象就不会被回收。除了强引用之外,Java中还设计了几种其他引用方式:

  1. 强引用:类似 “Object obj = new Object()” 这类的引用,就是强引用,只要强引用存在,垃圾收集器永远不会回收被引用的对象。
  2. 软引用:软引用相对于强引用是一种比较弱的引用关系,如果一个对象只有软引用关联到它,当程序内存不足时,就会将软引用中的数据进行回收。
  3. 弱引用:弱引用的强度比软引用更弱一些,弱引用包含的对象在垃圾回收时,不管内存够不够都会直接被回收。
  4. 虚引用:最弱的一种引用关系,虚引用唯一的用途是当对象被垃圾回收器回收时可以接收到对应的通知。常规开发中是不会使用的。

垃圾收集算法


        垃圾回收的核心算法:释放不再存活对象的内存,使得程序能再次利用这部分空间。下图为垃圾收集的四种算法

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

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

相关文章

16_C语言编程基础

目录 C语言入门 程序段和代码段 C语言入门实例 英文分号(;) 注释 标识符 保留字 C中的空格 C数据类型 基本类型 sizeof获取存储字节 void类型 变量 C数组 C枚举 C中的左值(lvalue)和右值(rvalue) C常量 变量存储类型 C常用关键字(保留字) 宏定义#define co…

生成式AI:未来商业的变革者

在2023年&#xff0c;生成式人工智能&#xff08;GenAI&#xff09;的浪潮席卷了全球&#xff0c;成为科技领域最炙手可热的话题之一。它不仅改变了我们与机器的互动方式&#xff0c;更在商业创新和生产力提升方面发挥了巨大的作用。本文将深入探讨2024年生成式AI的应用模式、趋…

docker初始化运行mysql容器时自动导入数据库存储过程问题

问题&#xff1a;用navicat导出的数据库脚本&#xff0c;在docker初始化运行mysql容器时&#xff0c;导入到存储过程时出错。 ERROR 1064 (42000) at line 2452: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for t…

面经-数据库

1.MySQL 1.1什么是MySQL? MySQL 是⼀种关系型数据库&#xff0c;在 Java 企业级开发中⾮常常⽤&#xff0c;因为 MySQL 是开源免费的&#xff0c;并 且⽅便扩展。阿⾥巴巴数据库系统也⼤量⽤到了 MySQL &#xff0c;因此它的稳定性是有保障的。 MySQL 是开放源代码的&…

微信小程序-插槽slot

一.插槽slot 在页面使用自定义组件的时候&#xff0c;如果在自定义组件里面写子组件&#xff0c;子组件的内容无法显示。 <custom01> <text slotslot-top>你好&#xff0c;上方组件</text> 你好&#xff0c;组件 <text slotslot-bottom>你好&#xf…

三层限流:为高并发系统保驾护航

文章目录 前言第一层限流&#xff1a;Nginx 层面的 IP 限流第二层限流&#xff1a;Gateway 对用户层级的限流第三层限流&#xff1a;微服务限流分布式限流和单机限流的优缺点&#xff1a;1、RateLimiter的使用2、Hystrix的使用3、Redislua脚本4、使用Sentinel 关于为何同时使用…

做PFMEA的经验之谈

在制造业的广袤领域中&#xff0c;PFMEA&#xff08;过程失效模式与影响分析&#xff09;是一项至关重要的工具&#xff0c;它用于识别并评估生产过程中的潜在失效模式&#xff0c;以及这些失效模式可能导致的后果。作为一名在制造业有多年经验的专业机构&#xff0c;深圳天行健…

安装KB5039212更新卡在25% 或者 96% 进度

系统之家7月1日消息&#xff0c;微软在6月11日的补丁星期二活动中&#xff0c;为Windows 11系统推出了KB5039212更新。然而&#xff0c;部分用户在Windows社区中反映&#xff0c;安装过程中出现失败&#xff0c;进度条在25%或96%时卡住。对于遇到此类问题的Windows 11用户&…

【论文复现|智能算法改进】基于自适应动态鲸鱼优化算法的路径规划研究

目录 1.算法原理2.改进点3.结果展示4.参考文献5.代码获取 1.算法原理 SCI二区|鲸鱼优化算法&#xff08;WOA&#xff09;原理及实现【附完整Matlab代码】 2.改进点 非线性收敛因子 WOA 主要通过控制系数向量 A 来决定鲸鱼是搜索猎物还是捕获猎物&#xff0c;即系数向量 A 可…

【LLM 论文】Self-Refine:使用 feedback 迭代修正 LLM 的 output

论文&#xff1a;Self-Refine: Iterative Refinement with Self-Feedback ⭐⭐⭐⭐ CMU, NeurIPS 2023, arXiv:2303.17651 Code: https://selfrefine.info/ 论文速读 本文提出了 Self-Refine 的 prompt 策略&#xff0c;可以在无需额外训练的情况下&#xff0c;在下游任务上产…

蒂升电梯职业性格和Verify认知能力SHL测评答题攻略及薪资待遇解密!

​一、蒂升电梯职业性格和认知能力测评考什么 您好&#xff01;蒂升电梯公司邀请您参加的OPQ职业性格测评和Verify认知能力测评是两种常见的评估工具&#xff0c;用于帮助了解个人的职场性格特点和认知能力。 OPQ职业性格测评 这是一种性格测试&#xff0c;通常用于评估个人在…

PostgreSQL介绍与安装

一、PostgreSQL数据库介绍 1、什么是数据库&#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库。每个数据库都有一个或多个不同的 API 用于创建&#xff0c;访问&#xff0c;管理&#xff0c;搜索和复制所保存的数据。 我们也…

倒装COB显示屏与传统SMD显示屏安装方式有哪些不同?

COB显示屏与传统SMD显示屏是商业显示领域中非常重要的两种载体&#xff0c;在前面的文章当中我们为大家阐述了倒装COB显示屏的技术特点&#xff0c;今天跟随COB显示屏厂家深圳市中品瑞科技一起来看看&#xff0c;COB显示屏的安装与传统LED显示屏的安装有哪些不同&#xff1f; 一…

数据结构之“刷链表题”

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;数据结构 目录 前言 一、相交链表 题目链接 大致思路 代码实现 二、环形链表1 题目链接 大致思路 代码实现 三、环形链表2 题目链接 大致思路 代码实…

爬虫逆向实战(41)-某巢登陆(AES、MD5、RSA、滑块验证码)

一、数据接口分析 主页地址&#xff1a;某巢 1、抓包 通过抓包可以发现在登录时&#xff0c;网站首先请求captcha/querySlideImage/来获取滑块验证码的图片&#xff0c;然后请求captcha/checkCode/接口来验证滑块验证码。滑块验证码校验成功后&#xff0c;请求noshiro/getPu…

论坛万能粘贴手(可将任意文件转为文本)

该软件可将任意文件转为文本。 还原为原文件的方法&#xff1a;将得到的文本粘贴到记事本&#xff0c;另存为UUE格式&#xff0c;再用压缩软件如winrar解压即可得到原文件。建议用于小软件。 下载地址&#xff1a;https://download.csdn.net/download/wgxds/89505015 使用演示…

Kafka 位移

Consumer位移管理机制 将Consumer的位移数据作为一条条普通的Kafka消息&#xff0c;提交到__consumer_offsets中。可以这么说&#xff0c;__consumer_offsets的主要作用是保存Kafka消费者的位移信息。使用Kafka主题来保存位移。 消息格式 位移主题就是普通的Kafka主题。也是…

HCIE实验这样玩太高级了吧?实现FRR+BFD+OSPF与BGP的联动

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 今天搞个HCIE实验玩玩&#xff0c;上回分享了个张总讲解的防火墙配置实验思路&#xff0c;后来还特地搞了个视…

GPT-4o文科成绩超一本线,理科为何表现不佳?

目录 01 评测榜单 02 实际效果 什么&#xff1f;许多大模型的文科成绩竟然超过了一本线&#xff0c;还是在竞争激烈的河南省&#xff1f; 没错&#xff0c;最近有一项大模型“高考大摸底”评测引起了广泛关注。 河南高考文科今年的一本线是521分&#xff0c;根据这项评测&…