JVM相关-JVM模型、垃圾回收、JVM调优
一、JVM模型
JVM内部体型划分
JVM的内部体系结构分为三部分,分别是:类加载器(ClassLoader)子系统、运行时数据区(内存)和执行引擎
1、类加载器
概念
每个JVM都有一个类加载器子系统(class loader subsystem),JVM的类加载器包括:用户自定义类加载器、应用类加载器、拓展类加载器、启动类加载器
-
启动类加载器(BootstrapClassLoader)
非java语言实现
作用:加载指定路径中jar里面的class文件
路径1:java安装目录\jre\lib
路径2:java安装目录\jre\classes
例如:rt.jar -
扩展类加载器(ExtClassLoader)
java语言实现,是ClassLoader类型的对象
作用:加载指定路径中jar里面的class文件( 只能是jar中存在的class)
路径:java安装目录\jre\lib\ext
例如:ext中默认存在的jar,或者用户放到ext目录下的jar包 -
应用类加载器 (AppClassLoader)
java语言实现,是ClassLoader类型的对象
作用:加载指定路径中class文件或者jar里面的class文件
路径:CLASSPATH中配置路径,这个是用户自己配置的
例如:.:bin:hello.jar
JVM的类加载机制
-
全盘负责
所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
-
双亲委派
双亲委派机制(如上图),当一个Hello.class这样的文件要被加载时。不考虑我们自定义类加载器,首先会在应用类加载器(如果存在用户自定义类加载器则从用户自定义类加载器开始)中检查是否加载过,如果有就无需再加载。如果没有,那么会拿到父加载器,然后调用父加载器的loadClass方法。父类中同理也会先检查自己是否已经加载过,如果没有再往上。这个类似递归的过程,直到到达启动类加载器之前,都是在检查是否加载过,并不会选择自己去加载。直到启动类加载器,已经没有父加载器了,这时候开始考虑自己是否能加载了,如果自己无法加载,会下沉到子加载器去加载,一直到最底层,如果没有任何加载器能加载,就会抛出ClassNotFoundException异常双亲委派机制的优势
采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以
避免类的重复加载
,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改
-
缓存机制
缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因
作用
java中的类,想要运行就必须把类对应的class文件加载到内存,JVM中真正负责加载class文件内容的是类加载器
负责将Java字节码文件(class文件)加载进JVM内存(运行时数据区)
2、 执行引擎
概念
每一个Java虚拟机都有一个执行引擎(execution engine)
作用
负责执行被加载类中包含的指令
3、 运行时数据区
运行时数据区又可以分为两大部分:
1、线程共享(堆区、方法区)
2、线程私有(程序计数器、Java虚拟机栈、本地方法栈)
3.1 程序计数器
-
概念
程序计数器就是记录当前线程执行程序的位置,通过改变计数器的值来确定执行的下一条指令,比如循环、分支、方法跳转、异常处理,线程恢复都是依赖程序计数器来完成
Java虚拟机多线程是交替运行的。为了线程切换能恢复到正确的位置,每条线程都需要一个独立的程序计数器,所以它是线程私有的
如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。此内存区域是唯一一个在Java虚拟机中没有内存溢出情况的区域
-
作用
存储指向下一条指令的地址。由于Java虚拟机多线程是根据时间片交替运行的,使用程序计数器可以使线程切换能恢复到正确的位置
3.2 Java虚拟机栈
-
概念
Java虚拟机栈是线程私有,生命周期与线程相同。创建线程的时候就会创建一个java虚拟机栈
虚拟机执行java程序的时候,每个方法都会创建一个栈帧,栈帧存放在java虚拟机栈中,通过压栈出栈的方式进行方法调用
栈帧又分为一下几个区域:局部变量表、操作数栈、动态连接、方法返回地址等
平时我们所说的变量存在栈中,这句话说的不太严谨,应该说局部变量存放在java虚拟机栈的局部变量表中
Java的8中基本类型的局部变量的值存放在虚拟机栈的局部变量表中,如果是引用型的变量,则只存储对象的引用地址
-
作用
实现方法的调用
3.3 本地方法栈
本地方法:native关键字修饰,非java语言实现的方法。例如,java调用C语言,来操作某些硬件信息
本地方法栈为虚拟机使用到本地方法服务(native)。本地方法栈为线程私有,功能和虚拟机栈非常类似。线程在调用本地方法时,来存储本地方法的局部变量表,本地方法的操作数栈等信息
3.4 堆区
堆是被所有线程共享的区域,在虚拟机启动时创建。堆里面存放的都是对象的实例(new 出来的对象都存在堆中)
我们平常所说的垃圾回收,主要回收的区域就是堆区
为了提升垃圾回收的性能,又对堆进行了新生代和年老代(比例1:2),根据不同对象生命周期的不同,存放在不同代中,使用不同的垃圾回收算法进行回收,效率更高
老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。
目前大部分垃圾收集器对于新生代都采取复制算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间(8:1:1),每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间
最新的创建的对象存放到Eden区,随着项目的运行,当对象占满Eden区,就会触发GC,执行引擎开启一个GC垃圾回收线程,利用可达性分析算法标记非垃圾对象,垃圾对象会被回收,非垃圾对象移动到Survior区,年龄+1(经历过一次垃圾回收没有被收集年龄+1),此时年经代使用的是复制算法进行垃圾回收。当对象的年龄达到15,会从Survivor区移动到老年代
而由于老年代的特点是每次回收都只回收少量对象,一般使用的是标记-整理算法(压缩法)
stw(stop the world)停止事件(用户线程暂停,专注垃圾回收),当Eden区堆满会触发Minior gc或young gc,当老年代堆满会触发Full gc,young gc 和 full gc都会引发stw,但是full gc引发的stw时间会比较长
3.5 方法区
方法区是被所有线程共享区域,用于存放已被虚拟机加载的类信息、常量、静态变量等数据
。被Java虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代(permanment generation)
永久代也会垃圾回收,主要针对常量池回收,类型卸载(比如反射生成大量的临时使用的Class等信息)。
常量池用于存放编译期生成的各种字节码和符号引用
,常量池具有一定的动态性,里面可以存放编译期生成的常量;运行期间的常量也可以添加进入常量池中,比如string的intern()方法
当方法区满时,无法在分配空间,就会抛出内存溢出的异常(OutOfMemoneyError)
Java8中已经没有方法区了,取而代之的是元空间(Metaspace)
4、 拓展理解
4.1 一个普通java程序的运行过程
- javac 将java源代码编译成class文件
- java 命令将class文件加载进JVM
- 类加载将class文件加载进方法区
- 此时初始化静态成员方法以及执行静态方法(先父后子,main方法本就是静态方法)
- 创建main线程
- 将main方法加载进java虚拟机栈
- 执行main方法中的代码
- 输出结果
4.2 各变量在内存中的位置
-
成员变量
作为对象的一部分存储在堆区中
-
局部变量
作为方法的一部分存放在栈区中。执行方法时,方法压栈;方法执行完毕,方法弹栈,局部变量也会消除
-
静态变量
方法区中
4.3 简单类执行过程
示例代码
class Student{private static country = "CN";private String name;private int age;public static void printlnCountry(){System.out.println(country);}public void showValue(){System.out.println(this.name);System.out.println(this.age);}public Student(String name, int age){this.String = name;this.age = age;}
}
public class Test{public static void main(String[] args){Student student = new Student("张三",20);student.showValue();Student.printlnCountry();}
}
上述类的执行过程:
-
首先Test类的字节码文件加载进方法区
-
Test静态方法区加载执行Test类的的静态变量、静态方法、main方法
-
main方法进栈
-
执行到 Student student = new Student(“张三”,20);
-
Student.class被加载进方法区
-
Student静态方法区加载执行Student类的静态变量、静态方法
-
在堆区开辟一个Student对象的空间,并赋予成员变量默认值,name = null;age = 0; 返回一个内存地址 9988#。成员变量赋值、匿名代码块、构造方法(如果存在则按此顺序执行)
-
构造方法 Student(String name, int age)压栈,this指向内存地址9988#,执行方法,弹栈
-
初始化堆区中的Student对象,为其赋值,name = “张三”;age = 20;
-
=赋值操作,将内存地址9988#指向student变量
-
-
showValue()方法压栈,this指向内存地址9988#,执行方法,弹栈
-
Student类的静态方法区的printlnCountry()方法压栈,执行方法,弹栈
-
main方法弹栈
-
等待JVM GC回收Student对象
二、JVM垃圾回收
举例:在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员;吃完直接就走的,是 Java 程序员。
相关概念
-
内存泄漏(Memory Leak)
使用完的对象不能及时回收
-
内存溢出(Out of Memory)
程序申请内存时没有足够的内存供程序使用,内存泄漏的堆积会造成内存溢出
对象回收判断
-
引用计数法
每一个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0的时候可以回收
-
可达性分析
从GcRoots开始向下搜索对象,搜索所走过的路径被称为引用链,当一个对象到GcRoots没有任何引用链相连时,则证明此对象是可回收的
可以作为GcRoots的对象有:
- 虚拟机栈中引用的对象
- 本地方法栈中(即一般说的native方法)引用的对象
- 方法区中静态属性引用的对象。
- 方法区中常量引用的对象
可达性算法中的不可达对象并不是立即死亡的,对象拥有一次自我拯救的机会,对象被系统宣告死亡至少要经历两次标记过程,第一次是经过可达性分析发现没有与GcRoots 相连接的引用链,第二次是对象执行finalize()方法后(收尾工作)即可被回收
当对象变成GcRoot不可达时,Gc会判断该对象是否覆盖了finalize方法,若未覆盖,则直接回收,否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法
常见的垃圾回收算法
-
标记-清除算法(Mark-Sweep)
分为两个阶段:标记阶段和清除阶段。标记阶段的任务是通过可达性分析标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间
从图中可以很容易看出标记-清除算法实现起来比较容易,但是有一个比较严重的问题就是
容易产生内存碎片
(就是导致可用内存不连续,零零散散的),碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作 -
复制算法
1969年Fenichel提出了一种称为“半区复制”(Semispace Copying)的垃圾收集算法,它
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉
,这样一来就不容易出现内存碎片的问题,但是存在空间浪费
的问题。具体过程如下图所示 -
标记-整理算法(标记-整理-清除)
为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,在通过可达性分析标记出可以被回收的对象,然后将存活对象都向一端移动,然后清理掉端边界以外的内存(
效率不高
)。(在标记清除的基础上对可利用内存进行整理)具体过程如下图所示:
-
分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。目前主流的分代垃圾回收算法是新生代使用复制算法,老年代使用标记-整理算法
典型的垃圾回收器
-
Serial/Serial Old收集器
最基本最古老的收集器,它是一个
单线程串行收集器
,并且在它进行垃圾收集时,必须暂停所有用户线程。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优点是实现简单高效,但是缺点是会给用户带来停顿 -
ParNew收集器
Serial收集器的多线程版本,即
多线程串行化收集器
,使用多个线程进行垃圾收集 -
Parallel Scavenge收集器
一个新生代的多线程收集器(
并行收集器
),它在回收期间不需要暂停其他用户线程,其采用的是Copying算法,该收集器与前两个收集器有所不同,它主要是为了达到一个可控的吞吐量,吞吐率(代码运行时间/代码运行时间+垃圾收集时间)优先,代码运行的时间更多 -
Parallel Old收集器
Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。
-
CMS(Concurrent Mark Sweep)收集器
一种以获取最短回收停顿时间为目标的收集器,它是一种
并发收集器
,采用的是Mark-Sweep算法执行阶段:
- 初始标记:可达性分析标记,会引发stw停止事件(停止用户线程)
- 并发标记:可以和用户线程并发执行
- 重新标记:重新标记,会引发stw停止事件
- 并发清除:可以与用户线程并发执行,不会引发stw停止事件
-
G1收集器
当今收集器技术发展最前沿的成果,它是一款
面向服务端应用的收集器
,它能充分利用多CPU、多核环境。因此它是一款并行与并发收集器
,并且它能建立可预测的停顿时间模型
三、JVM调优
何为性能调优?
- 根据项目需求对JVM规划和预调优
- 优化运行程序中JVM导致的卡顿
- 解决JVM运行中的各种问题
JVM调优参数
-Xms 设置 JVM堆内存初始空间大小,如-Xms2g
-Xmx 设置 JVM堆内存最大空间大小,如-Xmx2g
-Xmn 设置 JVM新生代空间大小,-Xmn1g
-XX:+UseG1GC 使用G1垃圾回收器
-XX:SurvivorRatio=8 设置survivor与eden的比例(1:8)
-XX:NewRatio=4 设置新生代和老年代的比例(1:4)
排查线上OOM
-
产生OOM的原因
-
一次性申请的对象太多
解决思路:更改申请对象的数量
-
内存资源耗尽未释放
解决思路:找到未释放的对象进行释放
-
本身内存资源不够
解决思路:使用命令jmap -heap [pid] 查看堆内存信息
可以通过jps(JavaVirtualMachine Process Status JVM进程状态)查看java进程id
示例:
[root@iZ7xvjebghrlinlgmirqudZ ~]# jmap -heap 669 Attaching to process ID 669, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.74-b02using thread-local object allocation. Mark Sweep Compact GCHeap Configuration:MinHeapFreeRatio = 40 #最小堆使用比例MaxHeapFreeRatio = 70 #最大堆可用比例MaxHeapSize = 1073741824 (1024.0MB) #最大堆空间大小NewSize = 89456640 (85.3125MB) #新生代分配大小MaxNewSize = 357892096 (341.3125MB) #最大新生代可分配大小OldSize = 178978816 (170.6875MB) #老年代分配大小NewRatio = 2 #survivor区与eden区比例(survivor)SurvivorRatio = 8 #survivor区与eden区比例(eden)MetaspaceSize = 21807104 (20.796875MB) #元空间(方法区)大小CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB #最大元空间大小G1HeapRegionSize = 0 (0.0MB) #G1单个Region大小Heap Usage: #堆使用情况 New Generation (Eden + 1 Survivor Space): #新生代capacity = 80609280 (76.875MB) #总容量used = 65509680 (62.47489929199219MB) #已使用free = 15099600 (14.400100708007812MB) #剩余容量81.26816168064025% used #使用占比 Eden Space: #eden区capacity = 71696384 (68.375MB)used = 61261624 (58.42363739013672MB)free = 10434760 (9.951362609863281MB)85.44590477533707% used From Space: #from survivorcapacity = 8912896 (8.5MB)used = 4248056 (4.051261901855469MB)free = 4664840 (4.448738098144531MB)47.661904727711395% used To Space: #to survivorcapacity = 8912896 (8.5MB)used = 0 (0.0MB)free = 8912896 (8.5MB)0.0% used tenured generation: #老年代capacity = 178978816 (170.6875MB)used = 41792568 (39.85649871826172MB)free = 137186248 (130.83100128173828MB)23.350566806744325% used30639 interned Strings occupying 3078128 bytes.
另外,可以通过命令
jmap -histo:live [pid] | more
查看JVM运行时最耗费资源的对象
-
-
如何定位以及解决办法
-
系统已经发生OOM到导致宕机了
提前设置内存溢出记录
Dump 文件是 Java 进程的内存镜像,其中主要包括 系统信息、虚拟机属性、完整的线程 Dump、所有类和对象的状态 等信息
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/temp/xxx.hprof -jar xxx.jar#JVM运行时导出Dump jmap -dump:file=[文件路径] [pid]
当内存溢出发生时可以根据生成的dump文件进行分析,快速定位问题所在
-
导出dump文件(JVM内存快照)
jamp -dump:file=[文件路径] [pid]
可能造成一次fullGC和一次STW
将导出的hhprof类型文件导入jvisualvm(java自带,在jdk的bin目录下)
-
结合jvisualvm进行调试
查看最多跟业务有关对象->找对GCRoot->查看线程栈。根据所得信息对代码进行优化
-
以上内容收集整理于网络,如有疏漏和错误的地方,欢迎指正~
相关文章:

JVM相关-JVM模型、垃圾回收、JVM调优
一、JVM模型 JVM内部体型划分 JVM的内部体系结构分为三部分,分别是:类加载器(ClassLoader)子系统、运行时数据区(内存)和执行引擎 1、类加载器 概念 每个JVM都有一个类加载器子系统(class l…...

提升图像分割精度:学习UNet++算法
文章目录 一、UNet 算法简介1.1 什么是 UNet 算法1.2 UNet 的优缺点1.3 UNet 在图像分割领域的应用 二、准备工作2.1 Python 环境配置2.2 相关库的安装 三、数据处理3.1 数据的获取与预处理3.2 数据的可视化与分析 四、网络结构4.1 UNet 的网络结构4.2 UNet 各层的作用 五、训练…...

排序算法---冒泡排序
原创不易,转载请注明出处。欢迎点赞收藏~ 冒泡排序是一种简单的排序算法,其原理是重复地比较相邻的两个元素,并将顺序不正确的元素进行交换,使得每次遍历都能将一个最大(或最小)的元素放到末尾。通过多次遍…...

基于数据挖掘的微博事件分析与可视化大屏分析系统
设计原理,是指一个系统的设计由来,其将需求合理拆解成功能,抽象的描述系统的模块,以模块下的功能。功能模块化后,变成可组合、可拆解的单元,在设计时,会将所有信息分解存储在各个表中࿰…...

数学建模-灰色预测最强讲义 GM(1,1)原理及Python实现
目录 一、GM(1,1)模型预测原理 二、GM(1,1)模型预测步骤 2.1 数据的检验与处理 2.2 建立模型 2.3 检验预测值 三、案例 灰色预测应用场景:时间序列预测 灰色预测的主要特点是模型使用的…...

智慧自助餐饮系统(SpringBoot+MP+Vue+微信小程序+JNI+ncnn+YOLOX-Nano)
一、项目简介 本项目是配合智慧自助餐厅下的一套综合系统,该系统分为安卓端、微信小程序用户端以及后台管理系统。安卓端利用图像识别技术进行识别多种不同菜品,识别成功后安卓端显示该订单菜品以及价格并且生成进入小程序的二维码,用户扫描…...

零基础学编程从入门到精通,系统化的编程视频教程上线,中文编程开发语言工具构件之缩放控制面板构件用法
一、前言 零基础学编程从入门到精通,系统化的编程视频教程上线,中文编程开发语言工具构件之缩放控制面板构件用法 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载—…...

【MySQL进阶之路】MySQL 中表空间和数据区的概念以及预读机制
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送! 在我后台回复 「资料」 可领取编程高频电子书! 在我后台回复「面试」可领取硬核面试笔记! 文章导读地址…...

JVM 性能调优 - 常用的垃圾回收器(6)
垃圾收集器 在 JVM(Java虚拟机)中,垃圾收集器(Garbage Collector)是负责自动管理内存的组件。它的主要任务是在程序运行过程中,自动回收不再使用的对象所占用的内存空间,以便为新的对象提供足够的内存。 JVM中的垃圾收集器使用不同的算法和策略来实现垃圾收集过程,以…...

【java】Hibernate访问数据库
一、Hibernate访问数据库案例 Hibernate 是一个在 Java 社区广泛使用的对象关系映射(ORM)工具。它简化了 Java 应用程序中数据库操作的复杂性,并提供了一个框架,用于将对象模型数据映射到传统的关系型数据库。下面是一个简单的使…...
从零开始手写mmo游戏从框架到爆炸(八)— byte数组传输
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客 Netty帧解码器 Netty中,提供了几个重要的可以直接使用的帧解码器。 LineBasedFrameDecoder 行分割帧解码器。适用场景:每个上层数据包,使…...

Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器
本工作簿演示了 Elasticsearch 的自查询检索器将非结构化查询转换为结构化查询的示例,我们将其用于 BM25 示例。 在这个例子中: 我们将摄取 LangChain 之外的电影样本数据集自定义 ElasticsearchStore 中的检索策略以仅使用 BM25使用自查询检索将问题转…...
uniapp的api用法大全
页面生命周期API uniApp中的页面生命周期API可以帮助开发者在页面的不同生命周期中执行相应的操作。常用的页面生命周期API包括:onLoad、onShow、onReady、onHide、onUnload等。其中,onLoad在页面加载时触发,onShow在页面显示时触发…...
笔记——asp.net core 中的 REST
REST(reprentational state transfer,表层状态转移) REST原则:提倡按照HTTP的语义使用HTTP。 如果一个系统符合REST原则,我们就说这个系统是Restful风格的。 在RPC风格的Web API系统中,我们把服务端的代码…...

排序算法---堆排序
原创不易,转载请注明出处。欢迎点赞收藏~ 堆排序(Heap Sort)是一种基于二叉堆数据结构的排序算法。它将待排序的元素构建成一个最大堆(或最小堆),然后逐步将堆顶元素与堆的最后一个元素交换位置,…...
Java字符串(包含字母和数字)通用排序
说明:本文章是之前查到的一篇安卓版的,具体原文路径忘记了。稍微改了一点,挺符合业务使用的! 一、看代码 /*** 包含数字的字符串进行比较(按照从小到大排序)*/private static Integer compareString(Stri…...

【Spring】springmvc如何处理接受http请求
目录 编辑 1. 背景 2. web项目和非web项目 3. 环境准备 4. 分析链路 5. 总结 1. 背景 今天开了一篇文章“SpringMVC是如何将不同的Request路由到不同Controller中的?”;看完之后突然想到,在请求走到mvc 之前服务是怎么知道有请求进来…...

2024年安全员-B证证模拟考试题库及安全员-B证理论考试试题
题库来源:安全生产模拟考试一点通公众号小程序 2024年安全员-B证证模拟考试题库及安全员-B证理论考试试题是由安全生产模拟考试一点通提供,安全员-B证证模拟考试题库是根据安全员-B证最新版教材,安全员-B证大纲整理而成(含2024年…...
redis过期淘汰策略、数据过期策略与持久化方式
redis的过期淘汰策略 redis过期淘汰策略有很多,默认是no-eviction 不删除任何数据,内存不足存入会直接报错,可以在redis配置文件中进行设置,其中有两个非常重要的概念,LRU与LFU LRU表示最近最少使用,LFU为最少频率使用 又按照volatile已设置过期时间的数据集和allkeys所有数…...

Oracle Vagrant Box 扩展根文件系统
需求 默认的Oracle Database 19c Vagrant Box的磁盘为34GB。 最近在做数据库升级实验,加之导入AWR dump数据,导致空间不够。 因此需要对磁盘进行扩容。 扩容方法1:预先扩容 此方法参考文档Vagrant, how to specify the disk size?。 指…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...