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

JVM基础扫盲

什么是JVM

JVMJava设计者用于屏蔽多平台差异,基于操作系统之上的一个"小型虚拟机",正是因为JVM的存在,使得Java应用程序运行时不需要关注底层操作系统的差异。使得Java程序编译只需编译一次,在任何操作系统都可以以相同的方式运行。

在这里插入图片描述

JVM运行时区域划分

方法区

这里的方法区指的不是存放Java方法的区域,它主要存放的是元数据信息,例如:类信息、常量、静态变量、以及class文件在类加载时也会数据也会存放到方法区中。

堆区

堆区存储的则是对象实例,数组等。例如我们日常的new 操作就是在堆区分配一个空间存放对象实例。因为堆区是线程共享区域的,所以多线程情况下操作相同对象可能存在线程安全问题。

虚拟机栈和本地方法栈

虚拟机栈

我们日常对象实例的方法调用都是在虚拟机栈上运行的,它是Java方法执行的内存模型,存储着被执行方法的局部变量表、动态链表、方法入口、栈的操作用(入栈和出栈)。

由于虚拟机栈是栈结构所以方法调用按顺序压入栈中,就会倒序弹出虚拟机栈,例如我们的下面这段代码:

public void a(){
b();
}
public void b(){
c();
}public void c(){
}

当线程调用a方法时,优先为a产生一个栈帧A压入栈中,发现a方法调用了b方法,再为b产生一个栈帧B压入栈中,然后b再调用c方法,再为c产生一个栈帧C方法压入栈中。

在这里插入图片描述

c执行结束,优先弹出栈,然后是b,最后是a。

在这里插入图片描述

由上可以在Java中方法是可以嵌套调用的,但这并不意味方法可以无线层次的嵌套调用,当方法嵌套调用深度超过了虚拟机栈规定的最大深度,就会抛出StackOverflowError,而这个错误也常常发生在我们编写的无终止条件的递归代码中。

虚拟机栈属于线程独享,所以也就没有什么生命周期的概念,每个方法随着调用的结束栈空间也随之释放,所以栈的生命周期也可以理解为和线程生命周期是一致的。

这就使得我们虚拟机栈中的局部变量表可以被复用,例如某个虚拟机栈当前局部变量表被使用的索引为0-n,一旦虚拟栈执行的代码超过n位置,那么n之前的内存空间就可以被再次复用。

在这里插入图片描述

小结一下虚拟栈的特点:

  1. 是方法执行时的内存模型。
  2. 方法调用以栈帧形式压入栈中。
  3. 方法嵌套调用并将栈帧压入栈帧时,深度操作虚拟机栈最大深度会报StackOverflowError
  4. 虚拟机栈的局部变量表随着变量使用的完结,之前的内存区域可被复用。
  5. 栈的生命周期跟随线程,线程调用结束栈即可被销毁。
本地方法栈

下面这个带有native关键字的方法就是在本地方法,它就是本地方法栈管理的方法,其工作机制和特点是虚拟机栈是差不多的,所以这里就不多做介绍了。

private native void start0();

程序计数器

程序计数器和我们操作系统学习的程序计数器概念差不多,记录着当前线程下一条要执行的指令的地址,因为是线程独享的,所以程序计数器也是线程安全的。
需要注意的是程序计数器只有在记录虚拟机栈的方法时才会有值,对于native方法,程序计数器是不工作的。

小结

上文对运行时数据区域做了一个简单的介绍,这里我们就用一张图总结一下JVM运行时区域的结构。

在这里插入图片描述

类加载器

什么是类加载器

类加载器实现将编译后的class文件加载到内存,并转为为运行时区域划分的运行时数据结构,注意类加载器只能决定类加载,至于能不能运行则是由 Execution Engine 来决定。

在这里插入图片描述

类加载器的工作流程

类加载器工作顺序为:加载、验证、准备、解析、初始化、使用、卸载。其中验证、准备、解析这三个步骤统称为连接。

加载
  1. 将编译后class文件加载到内存。
  2. 将静态数据结构转换成方法区中运行时数据结构。
  3. 在堆区创建一个 java.lang.Class对象作为数据访问的入口。
连接
  1. 验证:验证这个class的类的方法是否会做出危害JVM的事情。
  2. 准备:在方法区为静态变量常见空间,并对其进行初始化,例如private static int a=3;,在此阶段就会在方法区完成创建,并初始默认值0。
  3. 解析:虚拟机将常量池内的符号引用转为直接引用,例如import java.util.ArrayList在此阶段就会直接转为指针或者对象地址。
初始化

将方法区中准备好的值,通过调用<cinit>完成初始化工作。<cinit>会收集好所有的赋值动作,例如上文的private static int a=3就是这时候完成赋值的。

卸载

当对象使用完成后,GC将无用对象从内存中卸载。

类加载器的加载顺序

其实类加载器并非只有一个,按照分类我们可以将其分为:

BootStrap ClassLoader:rt.jar
Extention ClassLoader: 加载扩展的jar包
App ClassLoader:指定的classpath下面的jar包
Custom ClassLoader:自定义的类加载器

所以,为了保证JDK自带rt.jar的类能够正常加载,就出现了一种名为双亲委派的类加载机制。
举个例子,JDK自带的包中有一个名为String的类,而我们自定义的代码中也有一个String类,我们自己的类肯定是由App ClassLoader完成加载,如果我们的类加载器优先执行,那么JDK自带的String类就无法被使用到。

在这里插入图片描述

所以双亲委派机制就规定了类加载优先由BootStrap ClassLoader先加载,只有根加载器加载不到需要的类,才会交由下层类完成加载。
正是因为双亲委派机制的存在,jdk自带的String类才能够正常的使用,而我们也无法通过自定义String类进行重写。

小结

类加载器的工作流程为:

  1. 加载class文件到方法区并转为运行时数据结构,并在堆区创建一个Class对象作为入口
  2. 验证class的类方法是否由危害JVM的行为
  3. 准备阶段初始化静态变量数据
  4. 解析阶段将符号引用转为可以可直接导向对象地址的直接引用
  5. 初始化阶段通过cinit方法初始化对象实例变量等数据
  6. 使用完成后该类就会被卸载。

用一段代码解释Java文件是如何被运行的

如下所示,我们编写一个Student 类,他有name这个成员属性。

/*** 学生类*/
public class Student {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}

然后我们编写一个main方法,调用student类,完成属性赋值。

public class Main {public static void main(String[] args) throws InterruptedException {Student student = new Student();student.setName("小明");}}
  1. 首先编译得到Main.class文件后,系统会启动一个JVM进程,从classpath中找到这个class的二进制文件,将在到方法区的运行时数据区域。

在这里插入图片描述

然后发现有个主入口main方法,将main方法压入栈中。

在这里插入图片描述

main方法中需要new Student();,JVM发现方法区中没有Student类的信息,于是开始加载这个类,将这个类的信息存放到方法区,并在堆区创建一个Class对象作为方法区信息的入口。

在这里插入图片描述

new Student();在此时就会根据类元信息获取创建student对象所需要的空间大小,在堆区申请并开辟一个空间调用构造函数创建Student实例。

在这里插入图片描述

main方法调用setNamestudent 的引用找到堆区的Student,通过其引用找到方法区中Student 类的方法表得到方法的字节码地址,从而完成调用。

在这里插入图片描述

上述步骤完成后,方法按照入栈顺序后进先出的弹出,虚拟机栈随着线程一起销毁。

虚拟机堆

区域划分

JVM将堆内存分为年轻代和老年代。以及非堆内存区域,我们称为永久代,这里所说的永久代只有在Java8之前才会出现。在Java8之后因为兼容性原因,永久代的东西都被放置到元空间,元空间所使用的内存都是本地内存,这里的本地内存说的就是我们物理机上的内存,所以理论上物理机内存多大,元空间内存就可以分配多大,元空间大小分配和JVM从物理机上分配的内存大小没有任何关系。

补充元空间两个参数:

	MetaspaceSize:初始化元空间大小,控制发生GCMaxMetaspaceSize:限制元空间大小上限,防止占用过多物理内存。

在这里插入图片描述

年轻代

了解整体空间之后,我们再来聊聊年轻代,年轻又可以分为EdenSurvivor区,Survivor区又被平均分为两块。所以年代整体比例为8:1:1。当然这个值也可以通过-XX:+UsePSAdaptiveSurvivorSizePolicy来调整。

任何对象刚刚创建的时候都会放在Eden区。我们都知道堆区内存是共享的,所以Eden区的空间也是多线程共享的,但是为了确保多线程彼此之间相对独立(注意是线程之间彼此独立而不是操作Eden区对象独立),Eden区会专门划出一块连续的空间给每个线程分配一个独立空间,这个空间叫做TLAB空间。每个线程都可以操作自己的TLAB空间和读取其他线程的TLAB空间。

在这里插入图片描述

一旦Eden区满了之后,就会触发第一次Minor GC,就会将存活的对象从Eden区放到Survivor区。

Survivor区就比较特别了,它分为Survivor0和Survivor1区。JVM使用from和to两个指针管理这两块区域,其中from指针指向有对象的区域空间,to指针指向空闲区域的Survivor空间。

在这里插入图片描述

从Eden区中存活下来首先会在Survivor0区(此时from指针在Survivor0),一旦下一次Eden区空间满了之后就再次触发 Minor GC 将Eden区和Survivor0区存活的对象复制到Survivor1区,然后from指针指向Survivor1,结束一次minor GC。

在这里插入图片描述

经过15次之后还活着的对象就会被存放到老年代,这里是15是由-XX:MaxTenuringThreshold指定的, -XX:MaxTenuringThreshold 占4位,默认配置为15
这里补充一下,同样会将Survivor存放到老年代的第2个条件,当Survivor区对象比例达到XX:TargetSurvivorRatio时,也会将存活的对象放到老年区。

老年代

老年代存放的都是经历过无数次GC的老对象,一旦这个空间满了之后就会出现一次Full GCFull GC期间所有线程都会停止手头工作等待Full GC完成,所以在此期间,系统可能会出现卡顿现象。
这就意味着在高并发多对象创建场景的情况下,我们需要合理分配老年区的内存。一旦Full GC后还是无法容纳新对象,就会报OOM问题。

JVM如何判断对象是否需要被销毁

引用计数器法

这种了解就好了,一个对象被引用时+1,被解除引用时-1。我们根据引用计数结果决定是否GC,但是这种方式无法解决两个对象互相引用的情况。例如我们栈区没有一个引用指向当前两个对象,可堆区两个对象却互相引用对方。

在这里插入图片描述

可达性分析法

将一系列的GC ROOTS作为起始的存活对象集,查看是否有任意一个GC ROOTS可以到达这个对象,都不可达就说明这个对象要被回收了。

而以下几种可以作为GC ROOTS:

  1. 虚拟机栈中的局部变量等,被该变量引用的对象不可回收。
  2. 方法区的静态变量,被该变量引用的对象不可回收。
  3. 方法区的常量,被该变量引用的对象不可回收。
  4. 本地方法栈(即native修饰的方法),被该变量引用的对象不可回收。
  5. 未停止且正在使用该对象的线程,被该线程引用的对象不可回收。

在这里插入图片描述

判断对象是否需要真正回收

判断对象是否被回收需要经过两个阶段:

  1. 经过上文介绍的可达性分析法发现不可达的对象后,就将其第一次标记一下,然后判断该对象的是否要执行finalize()方法,若确定则将其存到F-Queue中。
  2. F-Queue中的对象调用finalize(),若此时还是没有任何引用链引用,则说明这个对象要被回收了。

垃圾回收算法(重点)

标记清除法

如下图,这种算法很简单,标记出需要被回收的对象的空间,然后直接清除。同样的缺点也很明显,容易造成内存碎片,内存碎片也很好理解,回收的对象空间都是一小块一小块的,当我们需要创建一个大对象时就没有一块连续大空间供其使用。

在这里插入图片描述

复制算法

这种算法和上文说的survivor一样,将空间一分为二,from存放当前活着的对象,to作为空闲空间。在进行回收时,将没有被标记回收的对象挪到另一个空间,然后from指向另一个空间。这种算法缺点也很明显,可利用空间就一半。

在这里插入图片描述

标记整理

这种算法算是复制算法的改良版,将存活对象全部挪动到一段,确保空闲和对象空间都是连续的,且空间利用率100%。

在这里插入图片描述

分代收集算法(综合算法)

这种算法就是上面算法的组合,即年轻代存活率低,采用复制算法。老年代存活率高,采用标记清除算法或者标记整理算法

JVM常见工具介绍

jinfo(查看配置信息)

查看Java应用程序配置参数或者JVM系统属性,相关命令详情我们可以使用-help或者man命令查看,如下所示:

[root@xxxxxtmp]# jinfo -help
Usage:jinfo [option] <pid>(to connect to running process)jinfo [option] <executable <core>(to connect to a core file)jinfo [option] [server_id@]<remote server IP or hostname>(to connect to remote debug server)where <option> is one of:-flag <name>         to print the value of the named VM flag-flag [+|-]<name>    to enable or disable the named VM flag-flag <name>=<value> to set the named VM flag to the given value-flags               to print VM flags-sysprops            to print Java system properties<no option>          to print both of the above-h | -help           to print this help message

为了演示,笔者在服务器上开启了一个Java应用,我们可以使用jps命令查看其进程id,可以看到笔者服务器中有一个pid19946的Java进程。

[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]# jps
20104 Jps
19946 jar

查看当前应用所有的配置参数以及系统配置属性命令为jinfo pid如下所示:

[root@xxxxx tmp]# jinfo 19946
Attaching to process ID 19946, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
Java System Properties:java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.202-b08
sun.boot.library.path = /root/jdk8/jre/lib/amd64
java.protocol.handler.pkgs = org.springframework.boot.loader
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = :
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level = unknown
sun.java.launcher = SUN_STANDARD
user.country = US
user.dir = /tmp......

如果我们希望查看当前Java应用是否有配置某些信息,可以使用命令jinfo -flag 配置选项 pid,例如我们想查看当前应用是否有开启gc选项,可以使用下面这段命令

可以看到输出结果为-XX:-PrintGC,因为PrintGC前面是减号,这说明该选项并没有开启。

[root@xxx tmp]# jinfo -flag PrintGC 19946
-XX:-PrintGC

如果我们希望将这个选项开启,我们只需在参数前面加个+号即可,例如我们希望开启gc选项,我们只需键入如下命令

[root@xxxxxtmp]# jinfo -flag +PrintGC 19946

再次查看可以发现,选项生效了

[root@xxxx tmp]# jinfo -flag PrintGC 19946
-XX:+PrintGC

有些参数是键值对的形式,例如我们想配置dump日志的路径,我们也可以使用jinfo进行配置,命令格式为jinfo -flag 参数=值 Java进程id

jinfo -flag HeapDumpPath=/tmp/dump.log 19946

打印JVM选项信息

jinfo -flags 4854
Attaching to process ID 4854, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
Non-default VM flags: -XX:CICompilerCount=2 -XX:HeapDumpPath=null -XX:InitialHeapSize=33554432 -XX:MaxHeapSize=511705088 -XX:MaxNewSize=170524672 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=11141120 -XX:OldSize=22413312 -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps
Command line:

查看应用属性,命令格式jinfo -sysprops Java进程id

jinfo -sysprops 2341

jmap(查看堆区信息、对象信息等)

jmap作用:

  1. 查看使用的GC算法,堆的配置信息以及各个内存区域的内存使用情况
  2. 显示堆对象的统计信息,包括每一个Java类、对象数量、内存大小、类名称等
  3. 打印等会回收的对象的信息
  4. 生成dump文件,配合jhat使用

查看堆内存使用情况 jmap -heap Java进程id

[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]# jmap -heap 25534
Attaching to process ID 25534, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08using thread-local object allocation.
Mark Sweep Compact GCHeap Configuration:MinHeapFreeRatio         = 40MaxHeapFreeRatio         = 70MaxHeapSize              = 511705088 (488.0MB)NewSize                  = 11141120 (10.625MB)MaxNewSize               = 170524672 (162.625MB)OldSize                  = 22413312 (21.375MB)NewRatio                 = 2SurvivorRatio            = 8MetaspaceSize            = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize         = 17592186044415 MBG1HeapRegionSize         = 0 (0.0MB)

查看存活的Java对象(文档说明:to print histogram of java object heap; if the “live” suboption is specified, only count live objects),命令格式: jmap -histo:live Java进程id

[root@xxxtmp]# jmap -histo:live 25534num     #instances         #bytes  class name
----------------------------------------------1:         48676        7974952  [C2:          7762        1873312  [I3:         47785        1146840  java.lang.String4:         12737        1120856  java.lang.reflect.Method5:          8773         968912  java.lang.Class6:         25572         818304  java.util.concurrent.ConcurrentHashMap$Node7:         14108         564320  java.util.LinkedHashMap$Entry8:          2712         509536  [B9:          9308         494936  [Ljava.lang.Object;10:          6345         493128  [Ljava.util.HashMap$Node;11:          7001         392056  java.util.LinkedHashMap12:         11255         360160  java.util.HashMap$Node13:         15946         354528  [Ljava.lang.Class;14:         18176         290816  java.lang.Object15:          3447         248184  java.lang.reflect.Field16:           124         192320  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  1. 打印正在被回收的类**(文档说明:to print information on objects awaiting finalization)**,命令格式:jmap -finalizerinfo Java进程id
[root@xxxtmp]# jmap -finalizerinfo 25534
Attaching to process ID 25534, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
Number of objects pending for finalization: 0

将存活的对象的信息存到二进制文件中

 jmap -dump:live,format=b,file=/tmp/heap.bin 25534
Dumping heap to /tmp/heap.bin ...
Heap dump file created

此时就可以使用jhat打开该文件,如下所示jhat 文件名,这时候我们就可以通过7000端口查看详情了。

[root@xxxtmp]# jhat heap.bin
Reading from heap.bin...
Dump file created Wed Nov 02 20:21:18 CST 2022
Snapshot read, resolving...
Resolving 346825 objects...
Chasing references, expect 69 dots.....................................................................
Eliminating duplicate references.....................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

jstat(常用,监控运行时状态信息)

jstat用于监控虚拟机各种运行状态信息,显示虚拟机进程中装在、内存、垃圾收集、JIT编译等运行数据。

查看类加载信息,命令格式jstat -class Java进程id

[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]# jstat -class 2341
Loaded  Bytes  Unloaded  Bytes     Time8221 14604.3        1     0.9      12.74
[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]#

查看编译统计信息jstat -compiler Java进程id


[root@xxxtmp]# jstat -compiler 2341
Compiled Failed Invalid   Time   FailedType FailedMethod4177      0       0    17.68          0
[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]#

查看gc统计信息

[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]# jstat -gc 2341S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
1408.0 1408.0  0.0   1020.3 11840.0   7493.1   29268.0    22168.5   42840.0 40613.5 5760.0 5311.9     65    0.401   2      0.213    0.613
[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]#

每个表头的含义如下

1. S0C :年轻代中第一个survivor(幸存区)的容量 (字节)
2. S1C :年轻代中第二个survivor(幸存区)的容量 (字节)
3. S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
4. S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
5. EC:年轻代中Eden(伊甸园)的容量 (字节)
6. EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
7. OC:Old代的容量 (字节)
8. OU:Old代目前已使用空间 (字节)
9. PC:Perm(持久代)的容量 (字节)
10. PU:Perm(持久代)目前已使用空间 (字节)
11. YGC:从应用程序启动到采样时年轻代中gc次数
12. YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
13. FGC:从应用程序启动到采样时old代(全gc)gc次数
14. FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
15. GCT:从应用程序启动到采样时gc用的总时间(s)

查看gc内存容量和元空间容量

[root@xxxtmp]# jstat -gccapacity 2341NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC10880.0 166528.0  14656.0 1408.0 1408.0  11840.0    21888.0   333184.0    29268.0    29268.0      0.0 1087488.0  42840.0      0.0 1048576.0   5760.0     65     2

查看年轻代统计信息

[root@xxxxtmp]# jstat -gcnew 2341S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT
1408.0 1408.0    0.0 1020.3  2  15  704.0  11840.0   7652.5     65    0.401
[root@iZ8vb7bhe4b8nhhhpavhwpZ tmp]#

参数详情

1. S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
2. S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
3. S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
4. S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
5. TT:持有次数限制
6. MTT:最大持有次数限制
7. EC:年轻代中Eden(伊甸园)的容量 (字节)
8. EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
9. YGC:从应用程序启动到采样时年轻代中gc次数
10. YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

补充

Minor GC、Major GC 和 Full GC 之间的区别

Minor GC,MajorGC、Full GC

minor gc 会发生stop the world 现象吗? - 红色的红的回答 - 知乎
https://www.zhihu.com/question/29114369/answer/2287094858

参考文献

大白话带你认识JVM

Java 性能调优实战

MaxTenuringThreshold 和 TargetSurvivorRatio参数说明

Java 堆内存是线程共享的!面试官:你确定吗?

Java8中的JVM元空间是不是方法区?

JVM中新生代为什么要有两个Survivor

jstat命令详解

JVM基础(三)一个对象的创建过程

相关文章:

JVM基础扫盲

什么是JVM JVM是Java设计者用于屏蔽多平台差异&#xff0c;基于操作系统之上的一个"小型虚拟机"&#xff0c;正是因为JVM的存在&#xff0c;使得Java应用程序运行时不需要关注底层操作系统的差异。使得Java程序编译只需编译一次&#xff0c;在任何操作系统都可以以相…...

SpringBoot基于gRPC进行RPC调用

SpringBoot基于gRPC进行RPC调用 一、gRPC1.1 什么是gRPC&#xff1f;1.2 如何编写proto1.3 数据类型及对应关系1.4 枚举1.5 数组1.6 map类型1.7 嵌套对象 二、SpringBoot gRPC2.1 工程目录2.2 jrpc-api2.2.1 引入gRPC依赖2.2.2 编写 .proto 文件2.2.3 使用插件机制生产proto相关…...

浏览器的事件循环机制(Event loop)

事件循环 浏览器的进程模型 何为进程&#xff1f; 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 何为线程&#xff1f; …...

THEMIS---Beta Sprint Summary Essay Blog

Which course does this assignment belong to2301-MUSE社区-CSDN社区云What are the requirements for this assignmentbeta SprintThe goal of this assignmentTo summarize the beta task progress and the teams sprintsTeam NameThemisTop-of-the-line collection of essa…...

Vue中实现分布式动态路由的基本实现步骤介绍

设想一下&#xff0c;我们在做一个体量非常大的项目&#xff0c;这个项目有很多的模块和相当多的页面。当我们想修改一个路由的时候&#xff0c;我们打开了router文件夹下的index.js文件时&#xff0c;一串长到鼠标滚轮需要滚大半天才滚到底的路由简直让人头皮发麻。 在开始之前…...

【Leetcode】计算器

思路 用栈来完成&#xff1b; 考虑到运算关系&#xff0c;先乘除后加减&#xff1b;此外&#xff0c;一般计算式首个数字式正数&#xff1b;判断字符是否为数字&#xff0c;str.isdigit()字符转数字&#xff1a;ord(str) - ord(‘0’)遇到加减符&#xff0c;压栈数字&#xf…...

巧妙的使用WPF中的资源

其实&#xff0c;在wpf中&#xff0c;最核心的就是xaml&#xff0c;因为只有xaml&#xff0c;才能体现出用的是wpf&#xff0c;而不是普通的cs文件&#xff0c;cs文件在winform中等等程序都可以使用的&#xff0c;唯独xaml才是wpf中最重要的&#xff0c;最精华的东西&#xff0…...

多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测

多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实现RIME-CNN-BiLSTM-Multihead-Attention多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现RIME-…...

【AIGC重塑教育】AI大模型驱动的教育变革与实践

文章目录 &#x1f354;现状&#x1f6f8;解决方法✨为什么要使用ai&#x1f386;彩蛋 &#x1f354;现状 AI正迅猛地改变着我们的生活。根据高盛发布的一份报告&#xff0c;AI有可能取代3亿个全职工作岗位&#xff0c;影响全球18%的工作岗位。在欧美&#xff0c;或许四分之一…...

【力扣100】2.两数相加

添加链接描述 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Op…...

算法leetcode|93. 复原 IP 地址(多语言实现)

文章目录 93. 复原 IP 地址&#xff1a;样例 1&#xff1a;样例 2&#xff1a;样例 3&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 93. 复原 IP 地址&#xff1a; 有效 IP …...

TOGAF—架构(Architecture)项目管理

一、简介 1.1概述 架构(Architecture)项目在本质上通常是复杂的。他们需要适当的项目管理来保持正轨并兑现承诺。本指南适用于负责规划和管理架构(Architecture)项目的人员。我们解释了如何用事实上的方法和标准(如PRINCE2或PMBOK)来补充TOGAF架构开发方法(ADM),以加…...

MVVM前端设计模式的发展与应用

在MVC模式中&#xff0c;随着代码量越来越大&#xff0c;主要用来处理各种逻辑和数据转化的Controller首当其冲&#xff0c;变得非常庞大&#xff0c;MVC的简写变成了Massive-View-Controller&#xff08;意为沉重的Controller&#xff09; 我曾经接手老项目&#xff0c;sprin…...

redis:二、缓存击穿的定义、解决方案(互斥锁、逻辑过期)的优缺点和适用场景、面试回答模板和缓存雪崩

缓存击穿的定义 缓存击穿是一种现象&#xff0c;具体就是某一个数据过期时&#xff0c;恰好有大量的并发请求过来&#xff0c;这些并发的请求可能会瞬间把DB压垮。典型场景就是双十一等抢购活动中&#xff0c;首页广告页面的数据过期&#xff0c;此时刚好大量用户进行请求&…...

php的Url 安全的base64编码解码类

/*** Url安全的Base64编码方法* author JerryLi* version 20231217*/ final class UrlSafeB64Fun{/*** 编码* param string $sData 原始字符串* return string*/static public function encode(string $sData): string{$aTmp base64_encode($sData);return strtr($aTmp, [>…...

安全CDN有什么作用,安全CDN工作原理是什么?

一、CDN的应用场景 CDN技术可以应用于各种类型的网站和应用程序&#xff0c;特别是对于以下几种场景&#xff0c;CDN的作用尤为明显&#xff1a; 1. 高流量网站&#xff1a;对于流量较大的网站&#xff0c;CDN可以将网站的内容分发到全球各地的节点上&#xff0c;从而分担服务…...

Mysql高可用|索引|事务 | 调优

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 文章目录 前言sql语句的执行顺序关键词连接名字解释sql语句 面试坑点存储引擎MYSQL存储引擎 SQL优化索引索引失效索引的数据结构面试坑点 锁事务四大特性事务的隔离级别MVCC 读写分离面试坑…...

电机驱动开发

最近在搞电机驱动程序&#xff0c;感觉很简单&#xff0c;实际操作却发现里面还有很多猫腻&#xff08;细节&#xff09;。 电机在嵌入式设备中非常常见&#xff0c;例如云台的转动&#xff0c;都是靠电机来驱动的。 电机常见分步进电机、直流电机&#xff0c;相对来说步进电机…...

基于PaddleNLP的深度学习对文本自动添加标点符号(一)

前言 目前以深度学习对文本自动添加标点符号研究很少&#xff0c;已知的开源项目并不多&#xff0c;详细的介绍就更少了&#xff0c;但对文本自动添加标点符号又在古文识别语音识别上有重大应用。 基于此&#xff0c;本文开始讲解基于PaddleNLP的深度学习对文本自动添加标点符号…...

“Java已死、前端已凉”?尊嘟假嘟?

一、为什么会出现“Java已死、前端已凉”的言论 “Java已死、前端已凉”的言论出现&#xff0c;主要是由于以下几个原因&#xff1a; 技术更新迅速&#xff1a;随着互联网技术的发展&#xff0c;新的编程语言和技术不断涌现。Java和前端技术作为广泛应用的技术&#xff0c;面临…...

双向无线功率传输系统MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介&#xff1a; 初级侧转换器通过双向 AC/DC 转换器从电网获取电力&#xff0c;并由直流线电压 Vin 供电&#xff0c;而拾波侧被视为连接到 EV&#xff0c;并由连接到任一存储的单独直流源 Vout 表示或…...

火山引擎DataLeap:助你实现从数据研发1.0到数据研发3.0的跨越

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 近日&#xff0c;火山引擎开发者社区 Meetup 第 12 期暨超话数据专场在深圳举办&#xff0c;本次活动主题为“数智化转型背景下的火山引擎大数据技术揭秘 ”&#x…...

DevOps 和人工智能 – 天作之合

如今&#xff0c;人工智能和机器学习无处不在&#xff0c;所以它们开始在 DevOps 领域崭露头角也毫不令人意外。人工智能和机器学习正在通过自动化任务改变 DevOps&#xff0c;并使各企业的软件开发生命周期更高效、更深刻和更安全。我们在 DevOps 趋势中简要讨论过这一问题&am…...

基于主动安全的AIGC数据安全建设

面对AIGC带来的数据安全新问题&#xff0c;是不是就应该一刀切禁止AIGC的研究利用呢&#xff1f;答案是否定的。要发展AIGC&#xff0c;也要主动积极地对AIGC的数据安全进行建设。让AIGC更加安全、可靠的为用户服务。为达到此目的&#xff0c;应该从三个方面来开展AIGC的数据安…...

Java 程序的命令行解释器

前几天我写了一个简单的词法分析器项目&#xff1a;https://github.com/MarchLiu/oliva/tree/main/lora-data-generator 。 通过词法分析快速生成 lora 训练集。在这个过程中&#xff0c;我需要通过命令行参数给这个 java 程序传递一些参数。 这个工作让我想起了一些不好的回忆…...

从事开发近20年,经历过各种技术的转变和进步

1、jsp、javabean、servlet、jdbc。 2、Struts1、hibernate、spring。 3、webwork、ibatis、spring 4、Struts2、mybatis、spring 5、spring mvc &#xff0c;spring全家桶 6、dubbo&#xff0c;disconf 微服务&#xff0c;soa 7、springboot 全家桶 8、docker 9、dock…...

unet v2学习笔记

unet v2介绍&#xff1a; UNet v2开源&#xff01;比UNet显存占用更少、参数更少&#xff0c;猛涨20个mIoU 代码&#xff1a;https://github.com/yaoppeng/U-Net_v2 模型96m。 实际测试&#xff0c;1060显卡&#xff0c;256*256&#xff0c;需要13ms。 速度慢于rvm人脸分割…...

MQ入门—centos 7安装RabbitMQ 安装

三&#xff1a;RabbitMQ 安装 1.环境准备 Linux 的 CentOS 7.x 版本。Xftp 传输安装包到 Linux。Xshell 连接 Linux&#xff0c;进行解压安装。 RabbitMQ安装包 链接&#xff1a;https://pan.baidu.com/s/1ZYVI4YZlvMrj458jakla9A 提取码&#xff1a;dyto xshell安装包 链接&…...

虾皮Shopee商品详情API:电商实时数据获取的关键

随着互联网的普及和电子商务的快速发展&#xff0c;电商行业已经成为全球范围内最具影响力和前景的产业之一。在电商行业中&#xff0c;商品详情API接口是实现快速、准确获取商品信息的关键技术之一。本文将介绍获得虾皮Shopee根据ID取商品详情 API在电商行业里的重要性&#x…...

VUE中的8种常规通信方式

文章目录 1.props传递数据(父向子)2.$emit触发自定义事件&#xff08;子向父&#xff09;3.ref&#xff08;父子&#xff09;4.EventBus&#xff08;兄弟组件&#xff09;5.parent或root&#xff08;兄弟组件&#xff0c;有共同祖辈&#xff09;6.attrs和listeners&#xff08;…...

建筑设计门户网站/什么是关键词广告

其实到现在为止 Swift 离替代 Objective-C 还是很遥远&#xff0c;因为 Apple 内部一直在用 Objective-C 来做一些 Framework 的开发&#xff0c;低层也不可能用 Swift 实现 — Cyan 如果把取代定义为编写底层框架的话, 至少以 Swift 3 来说, 毫无疑问是不可能的. 首先我们先去…...

门户网站开发一般多少钱/线下推广

约瑟夫问题 Time Limit: 1000ms Memory limit: 65536K 有疑问&#xff1f;点这里^_^ 题目描写叙述 n个人想玩残酷的死亡游戏&#xff0c;游戏规则例如以下&#xff1a; n个人进行编号&#xff0c;分别从1到n&#xff0c;排成一个圈&#xff0c;顺时针从1開始数到m&#xff0…...

对招聘公司做评价的网站/怎么做公司网页

WAVE文件格式剖析 WAVE文件作为多媒体中使用的声波文件格式之一&#xff0c;它是以RIFF格式为标准的。RIFF是英文Resource Interchange File Format的缩写&#xff0c;每个WAVE文件的头四个字节便是“RIFF”。WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFF&…...

金融行业做网站/爱站网挖掘关键词

有一位阿里员工在脉脉上&#xff0c;晒出了自己被辞退的经历&#xff1a; 35岁的他&#xff0c;欢天喜地过完年后&#xff0c;迎来的不是开门红包&#xff0c;而是公司的辞退建议。而被辞退的理由很简单&#xff1a;年纪太大。 都说工作经验决定收入水平&#xff0c;可是在这…...

设置网络的网站/口碑营销经典案例

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全生产模拟考试一点通&#xff1a;A特种设备相关管理&#xff08;电梯&#xff09;免费试题根据新A特种设备相关管理&#xff08;电梯&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将A特种设备相关管…...

电子网站建设实训/微信朋友圈推广

matlab中的的最大值和最小值MATLAB提供的求数据序列的最大值和最小值的函数分别为max和min&#xff0c;两个函数的调用格式和操作过程类似。1&#xff0e;求向量的最大值和最小值求一个向量X的最大值的函数有两种调用格式&#xff0c;分别是&#xff1a;(1) ymax(X)&#xff1a…...