【精华】JVM调优学习

news2024/11/30 14:23:55

JVM 介绍

1. 什么是 JVM

JVM 是 Java Virtual Machine(Java 虚拟机)的缩写。一台执行 Java 程序的机器。

2 .JAVA 语言的执行原理

计算机语言
计算机能够直接执行的指令。这种指令和系统及硬件有关。

计算机高级语言
在遵循语法的前提下,写一个文本文件,之后利用某种方式,把文本转换为计算机指令
执行。

A. 编译型语言(C 语言):文本文件(.c) --> 编译器 --> 可执行文件(.exe) -->
执行机器指令。特点:运行速度快,但不能跨平台

B. 解释型语言(JavaScript):文本文件 --> 解释器 --> 翻译成机器指令并执
行。特点:运行速度较慢,但能跨平台

JAVA 语言:先编译,后解释执行
文本文件(java) --> 编译器 --> class 文件(虚拟指令) --> JAVA 虚拟机(JVM)–> 解释为指令执行。

3.JDK+JRE+JVM

(1)JDK(IAVA开发环境)=:JRE+工具(编译器、调试器、其他工具)+类库
编译器:将JAVA文件编译为JVM能够看懂的文件(class文件)

(2)JRE(JAVA运行环境):JVM+JAVA解释器
Java解释器:将虚拟指令解释为机器指令执行。

(3)JVM(JAVA虚拟机)

在这里插入图片描述

4. JAVA字节码文件结构

在这里插入图片描述在这里插入图片描述

打开class文件查看结构
在这里插入图片描述在class字节码最前面都会有cafe babe
在这里插入图片描述
什么是 u2,u4?
u2:代表数据占两个字节
u4:代表数据占四个字节
在这里插入图片描述JDK 编译对应的版本号

  • JDK7 --> 51
  • JDK8 --> 52
  • JDK9 --> 53
  • JDK15 --> 59

结论

编译的本质就是将 java 源文件转为 JVM 能够认识的 16 进制 class 文件格式

三、 类加载机制

1 类加载过程

1.1 装载

(1)获取类的全限定类名,把 class 文件转为二进制流
(2)将二进制流中类的描述信息存入方法区中。如:创建时间、版本等… (3)将 java.lang.Class 对象存入堆中。

1.2 链接

(1)验证:验证被加载类的正确性:如文件的格式,元数据等。
(2)准备:在方法区中为静态变量分配空间,并设置初始值。

(3)解析:把类的符号引用转为直接引用。
符号引用:class 文件定义的内容
直接引用:JAVA 进程中真实的地址

1.3 初始化

为类的静态变量设置默认值、执行静态代码块。

2 类加载器

2.1 分类

不同的类加载器加载不同的类:

启动类加载器(Bootstrap classLoader): 主要负责加载 JAVA 中的 一些核心类库,主要是位于<JAVA_HOME>/lib/rt.jar 中。

拓展类加载器(Extension classLoader):主要加载 JAVA 中的一些拓展类,位于<JAVA_HOME>/lib/ext 中,是启动类加载器的子类。

应用类加载器(System classLoader): 主要用于加载 CLASSPATH 路径下我们自己写的类,是拓展类加载器的子类

2.2 双亲委派模型

如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给
父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。如果父类加载器可以完成类加载任务,就成功返回。
倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载。
在这里插入图片描述

四、 JVM 内存模型

1 什么是 JVM 内存模型

JVM 需要使用计算机的内存,Java 程序运行中所处理的对象或者算法都会使用 JVM 的内
存空间,JVM 将内存区划分为 5 块,这样的结构称之为 JVM 内存模型。

2 JVM 为什么进行内存区域划分

随着对象数量的增加,JVM 内存使用率也在增加,如果 JVM 内存使用率达到 100%,
则无法继续运行程序。为了让 JVM 内存可以被重复使用,我们需要进行垃圾回收。为了提
高垃圾回收的效率,JVM 将内存区域进行了划分。

3 JVM 内存划分

JVM 按照线程是否共享将内存首先分成两大类
线程独享区
只有当前线程能访问数据的区域,线程之间不能共享
线程独享区随线程的创建而创建,随线程的销毁而被回收
线程共享区
所有线程都可以访问的区域,
当线程被销毁的时候,共享区的数据不会立即回收,需要等待达到垃圾回收的阈(yu)
值之后才会进行回收。
在这里插入图片描述

4 程序计数器

程序计数器会记录当前线程要执行指令的内存地址,只占用一小部分内存区域,只记录一个
地址,所以我们认为程序计数器是不会出现内存溢出问题的分区。

5 本地方法栈

Java 中有些代码的实现是依赖于其他非 Java 语言的(C++),本地方法栈存储的是维护
非 Java 语句执行过程中产生的数据,一般我们认为本地方法栈不会出现内存的问题。

6 虚拟机栈

6.1 虚拟机栈的作用

存放当前线程中所声明的变量,包括基本数据类型的数据和引用数据类型的引用。
基本数据类型和引用数据类型划分的标准:

  • 基本数据类型:
    变量在声明的时候,能够确认占用内存的大小。
  • 引用数据类型:
    变量在声明的时候,不能确认占用内存的大小。
    引用数据类型将值的引用存放到虚拟机栈中,而对象存放在堆内存中,引用数据类型占用 4
    个字节存放地址

6.2 栈帧

每一个线程都会对应一个虚拟机栈,线程中的每个方法都会创建一个栈帧,存放本次方法执
行过程中所需要的所有数据。
如果我们一个线程中有多个方法的嵌套调用,虚拟机栈会对栈帧进行压栈和出栈操作。正在
执行的方法一定在栈顶,我们只能获取栈顶的栈帧,栈帧在虚拟机栈中先进后出。

6.3 栈帧的数据结构

局部变量
存放当前方法的局部变量,基本数据类型存值,引用数据类型存堆内存地址。
操作数栈
对方法中的变量提供计算的区域。
常量数据的引用
常量数据会存放到方法区的常量池中,不管是基本数据类型还是引用数据类型都会存放常量
池的地址
方法返回值的地址
方法返回数据会存到计算机内存的寄存器中。

6.4 虚拟机栈溢出异常

由于栈帧调用的深度太深,会出现虚拟机栈溢出异常(SOF 异常)。一般手动方法的调用
是不会出现这个异常的,如果出现这个异常 ,99%是由于递归。
可以通过修改虚拟机栈的内存大小设置栈帧的最大深度,指令为:

-Xss 虚拟机栈内存大小

一般栈帧深度达到 3000~5000 即可
太小:虚拟机栈容易溢出。
太大:每个线程占据的内存过大,影响线程数量。

7 方法区

在 java8 之后,我们把方法区称之为元空间(MetaSpace),方法区在逻辑上属于堆
的一部分,但一些具体机制和堆有所区别,如:一些 JVM 的方法区是可以不进行垃圾回收
的,关闭 JVM 时才会释放方法区内存。所以方法区还有一个别名叫非堆,目的是和堆分开。
方法区会存储类信息、静态变量、常量(JDK8 之后不存放字符串常量)、本地机器指
令。
如果加载大量 class 文件,也会造成方法区内存溢出,如一个 tomcat 运行 20~30 个
项目。

五、 JVM 执行引擎

1 什么是 JVM 执行引擎

执行引擎是 Java 虚拟机核心的组成部分之一。JVM 的将字节码装载到内存,但字节码
并不能够直接运行在操作系统之上。为了执行内存中的字节码文件指令,执行引擎
(Execution Engine)就要将字节码指令解释/编译为对应平台上的本地机器指令。

执行引擎的翻译过程有两种:
1、通过解释器将字节码文件转为机器指令执行;
2、使用即时编译器(JIT)将字节码文件的二进制流编译成机器指令执行。

目前市面的主流 JVM 采用解释器与即时编译器并存的架构。在 Java 虚拟机运行时,
释器
即时编译器相互协作,取长补短。在今天,Java 程序的运行性能早已脱胎换骨,已经
达到了可以和 C/C++程序一较高下的地步。

2 解释器与即时编译器

解释器每次解释都会将字节码文件解释为机器指令。整体效率较低,但当程序启动后, 解释器可以马上发挥作用,省去编译的时间,立即执行。

即时编译器则会将字节码文件编译为机器指令,存在方法区中,编译完成后直接执行本
地机器指令即可。编译器把代码编译成本地代码需要一定的执行时间,但编译为本地代码后
执行效率高。

当 Java 虚拟器启动时,解释器首先发挥作用,不必等待即时编译器全部编译完成后再
执行。随着时间的推移,编译器把越来越多的代码编译成本地代码,此时运行本地机器指令,
获得更高的执行效率。

六、 堆内存模型

JVM 将对象存放在堆内存中,堆内存所需要的空间是比较大的。我们对于 JVM 的调优
也主要是针对堆内存的调优,比如分配堆内存的空间,那么我们如何能确定堆内存需要分配
多少空间呢?我们需要大概计算每个对象所占的空间大小

1 JAVA 对象内存布局

在这里插入图片描述JAVA 对象在内存中主要有以下几部分:

对象头
MarkWord:一系列标记位(哈希码、分代年龄、锁状态标记等),在 64 位系统中占
8 字节。
ClassPoint:对象对应的类信息的内存地址,在 64 位系统中占 8 字节。
Length:数组对象特有,表示数组长度,占 4 字节。

实例数据
包含了对象的所有成员变量,大小由变量类型决定。
byte、boolean:1 字节
short:2 字节
char:2~3 字节
int、float:4 字节
long、double、引用数据类型:8 字节

对其填充
将对象大小填充为 8 字节的整数倍

2 JVM 内存溢出和垃圾回收机制

为什么要进行垃圾回收:
如果对象只创建不回收,会造成堆内存溢出(OOM)异常。
为什么要进行堆内存分区:

  • 提高搜索垃圾的效率。
  • 垃圾回收后可以更好的利用内存空间,存放大对象。
  • 尽可能减少 GC 次数。

3 JVM 堆内存的划分

老年代:

对象会优先分配到新生代内存中,每次 GC 后没有回收的对象年龄加 1,年龄到15 还没有被回收,对象会存放到老年代内存中;如果对象较大,超过新生代内存的一半,对象也会存放到老年代区域。

新生代:

为了减少young区垃圾回收后的空间碎片,新生代又分为Eden区和两个Survivor
区,且始终有一个 Suvivor 区保持闲置。对象会先存放到 Eden 区当中,Eden 区空间
满了之后会进行 young 区的垃圾回收,之后将 young 区所有存活的对象复制到闲置
的 Suvivor 区中,并清空 Eden 区和正在使用的 Survivor 区。

4 YoungGC 和 OldGC

YoungGC

新生代区域的垃圾回收称之为 YoungGC,也叫 MinorGC,Eden 区满后会触发YoungGC

OldGC

老年代区域的垃圾回收称之为 OldGC,也叫 MajorGC,OldGC 非常浪费性能,
所以我们的 JVM 调优要尽可能减少 OldGC 的次数, OldGC 往往伴随着 YoungGC。
YoungGC+OldGC = FullGC

问题:
- 1.Survivor 区空间并不大,如果满了怎么办?
(1)一般情况下 GC 会回收 95%的对象,且超过 15 次 GC 的对象会存放到 old
去,所以 Survivor 区不容易满。
(2)如果 Survivor 区满了,会触发担保机制,提前将对象存入 Old 区。

- 2.为什么需要 Survivor 区?
为了减少垃圾回收带来的空间碎片,空间碎片过多会频繁触发 YoungGC。

- 3.为什么需要两块 Survivor 区?
为了减少 Survivor 区的空间碎片。

七、 垃圾回收机制

堆内存模型设计是为了提高垃圾回收的效率,那么如何判断一个对象是垃圾?

1 如何判断一个对象是垃圾

引用计数法:

如果要操作对象,必须通过引用来进行。如果一个对象没有任何引用与之关联,则说明
该对象基本不太可能在其他地方被使用到。那么这个对象就成为可被回收的对象了。这种方
式实现简单,效率较高,但是它无法解决循环引用的问题,因此在 Java 中并没有采用这种
方式(Python 采用的是引用计数法)。

可达性分析:

以一个 GC Root 对象作为起点进行搜索,如果在 GC Roots 和对象之间没有可达路径,
则称该对象是不可达的。

GC ROOT 对象:

  • 栈帧中的本地变量表中引用的对象。
  • 方法区中静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中引用的对象。

2 垃圾回收算法

(1)标记——清除算法:效率较低,有空间碎片。Old 区使用的算法
在这里插入图片描述(2)复制算法:空间碎片少,但会浪费空间。存活对象较少才会使用的算法。young
区使用的算法
在这里插入图片描述
(3)标记——整理算法:空间碎片少,效率较低。Old 区使用的算法。

在这里插入图片描述

3 垃圾收集器的评判标准

垃圾收集器是对垃圾回收算法的实现,JVM 中提供了很多垃圾收集器,我们如何评判一个垃圾收集器的好坏呢?

垃圾收集器的执行效率 = 吞吐量 / 停顿时间
吞吐量 = 用户代码执行时间/(用户代码执行时间+停顿时间)

4 垃圾收集器的类型

  • 串行收集器:
    只有一个垃圾回收线程,在垃圾回收时暂停用户代码线程,如 Serial 和 Serial Old收集器。
    在这里插入图片描述
  • 并行收集器

吞吐量优先,多个垃圾收集器线程共同工作, 尽快完成垃圾收集。如 ParNew,Parallel Scanvenge, Parallel Old 收集器
在这里插入图片描述

  • 并发收集器

停顿时间优先,用户线程和垃圾回收线程一同工作,用户代码线程也会完全停止一小段时间,如CMS,G1 收集器。

在这里插入图片描述

5 CMS 收集器

CMS(concurrent mark sweep,并发标记扫描)收集器是并发收集器,是基于标记 ——清理的算法进行垃圾回收,用于 OldGC。

  • 优点:并发收集、低停顿
  • 缺点:会产生大量空间碎片,停顿时间虽然短但是不可控。

问:CMS 收集器为什么不进行并发的初始标记?
因为初始标记速度很快,不值得多开线程,开线程也是需要耗费资源的。

6 G1 收集器

G1(garbage first,垃圾优先)收集器是并发收集器,从 JDK1.7 开始支持,能进行OldGC 和 YoungGC。Old 区采用标记整理算法,Young 区采用复制算法。

G1 收集器没有固定的 Old、Young、Eden、Survivor 区,而是将内存分为一个个大小相等的 Region(格子,1Mb~32Mb)。每次垃圾回收后,Region 的用途可以发生改变,提高了内存的灵活性和利用率。
在这里插入图片描述G1 收集器可以根据开发者设置的参数,停顿时间的期望值,优先筛选回收存活的对象
比较少,垃圾对象比较大的区域 Region,可以把更多空余的空间释放出来。
在这里插入图片描述

7 ZGC 收集器

ZGC 从 JDK11 开始支持,目前还是一个实验性版本,原理类似 G1。是目前收集效率
最高的垃圾收集器,平均暂停时间为 0.05 毫秒。

8 如何选择垃圾收集器?

  • 优先让服务器自己来选择
  • 如果内存小于 100M,使用串行收集器
  • 如果服务器是单核,并且没有停顿时间要求,使用串行收集器
  • 如果允许停顿时间超过 1 秒,选择并行收集器
  • 如果停顿时间不能超过 1 秒,使用并发收集器

八、 JVM 参数设置

1 JVM 参数设置方式

Intellij idea:在运行设置的 VM Option 中设置。
tomcat:进入 Tomcat 的 bin 目录下,打开文件 catalina.bat/catalina.sh,修改如下
参数

set "JAVA_OPTS=参数"

2 JVM 参数类型

(1)标准参数:不随 jdk 版本的变化而变化的参数,如:-version
(2)-X 参数:不能保证所有的 JVM 都支持。
如:-Xcomp:使用即时编译器执行字节码文件
-Xint:使用解释器执行字节码文件
-Xmixed:混合模式,先使用解释器,即时编译器编译好后执行机器指令。
(3)-XX 参数:不能保证所有的 JVM 都支持。
A. Boolean 类型参数:
-XX:+UseG1GC:使用 G1 收集器
-XX:-UseG1GC:不使用 G1 收集器
B. Key-Value 类型参数:
-XX:MaxTenuringThreshold=15:对象年龄达到 15 就会进入老年代

3 常用参数

在这里插入图片描述

九、 JVM 常用命令和常用工具

1 JVM 常用命令

jps:查看当前执行的所有 JAVA 进程
jinfo:实时查看 JVM 参数
jinfo -flag InitialHeapSize PID:JAVA 进程堆内存大小
jinfo -flag UseG1GC PID:JAVA 进程是否使用 G1GC
jinfo -flag UseParallelGC PID:JAVA 进程是否使用 ParallelGC
jstat:虚拟机性能信息
jstat -class PID 1000:每秒查看一次虚拟机中类加载信息
jmap:打印快照
jmap -heap PID:查看堆存储快照
jmap -dump:format=b,file=heap.hprof PID:在出现内存溢出异常时,将堆内存的信息下载到文件中

十一、 JVM 调优思路

1 高并发环境下如何配置堆和垃圾回收器?在这里插入图片描述

2 生产环境 JVM 问题的排查

在这里插入图片描述

3 常见面试题补充

内存泄漏和内存溢出是一样的概念吗?

不一样,内存泄漏指不再使用的对象无法得到及时的回收,持续占用内存空间,造成内存空间的浪费。内存溢出指程序运行要用到的内存大于能提供的最大内存。内存无法内存泄漏很容易导致内存溢出,内存溢出不一定是内存泄漏导致的。

GC Root 不可达的对象一定会被回收吗?

不一定,不可达的对象也不是非死不可的,G1 收集器最终就会筛选要回收的对象。

方法区中的类会被回收吗?

有可能。需要满足以下三个条件:
(1)该类的所有的实例都已经被回收了。
(2)该类的 ClassLoader 已经被回收了。(3)java.lang.class 对象没有任何地方使用。

CMS 和 G1 的区别
cms 只能适用于老年代,g1 可以用于老年代和新生代。
cms 使用了标记——清除算法,会产生大量碎片,g1 使用标记——整理算法,减
少了碎片的产生。
g1 更加灵活,它将内存分为了一块块 region,并且停顿时间可控。

JVM内存区域

请添加图片描述

JVM执行引擎
请添加图片描述

堆内存模型
请添加图片描述

可达性分析
请添加图片描述

类加载过程
请添加图片描述

栈帧
请添加图片描述

栈帧的结构
请添加图片描述

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

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

相关文章

模块化建筑全球市场分析

模块化市场分析 市场摘要 全球模块化建筑市场&#xff0c;预计从2019年的1199亿6千万美元&#xff0c;到2027年的1916亿2千万&#xff0c;以6.4%的年复合成长率成长。人口增加&#xff0c;快速城市化和基础设施发展投资增加是预测期内刺激市场增长的关键因素。模块化施工是最可…

【C进阶】第十三篇——指针详解

指针的基本概念 指针类型的参数和返回值 指针与数组 指针与const限定符 指针与结构体 指向指针的指针与指针数组 指向数组的指针与多维数组 函数类型和函数指针类型 不完全类型和复杂声明 指针的基本概念 堆栈有栈顶指针&#xff0c;队列有头指针和尾指针&#xff0c;…

C++ 图进阶系列之纵横对比 Bellman-Ford 和 Dijkstra 最短路径求解算法

1. 前言 因无向、无加权图的任意顶点之间的最短路径由顶点之间的边数决定&#xff0c;可以直接使用原始定义的广度优先搜索算法查找。 但是&#xff0c;无论是有向、还是无向&#xff0c;只要是加权图&#xff0c;最短路径长度的定义是&#xff1a;起点到终点之间所有路径中权…

第五十讲:神州路由器IPv6隧道的配置

目前IPv6隧道技术有ISATAP隧道、6to4隧道、IPv6 over MPL隧道等。 任务一&#xff1a;配置ISATAP隧道 实验拓扑图如下所示 配置要求&#xff1a;两台路由器ROUTERA和ROUTERB通过IPv4网络连接&#xff0c;要求在两台路由器上分别配置ISATAP隧道&#xff0c;实现两端IPv6主机PC…

回收租赁商城系统功能拆解05讲-供货商

回收租赁系统适用于物品回收、物品租赁、二手买卖交易等三大场景。 可以快速帮助企业搭建类似闲鱼回收/爱回收/爱租机/人人租等回收租赁商城。 回收租赁系统支持智能评估回收价格&#xff0c;后台调整最终回收价&#xff0c;用户同意回收后系统即刻放款&#xff0c;用户微信零…

2022年学习和实习总结——收获颇多(未完待续...)

0 序言 时间已经进入了2023年&#xff0c;今年将是属于我们这一届秋招的一年。回顾2022年的学习和实习历程&#xff0c;我觉得今年的收获还是不少的&#xff0c;甚至可以说是整个高等教育生涯中&#xff0c;收获最多的一年。 1 学习情况总结 1.1 读书和学习总结 原来…

【Linux】项目构建自动化工具——make和makefile

make 和 makefile1.背景2. 利用make和makefile简单编译一个源文件3.使用方法解释4.执行原理5.项目清理1.背景 &#xff08;1&#xff09;一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的规则来指定&#xff…

智能驾驶视觉传感器测试:自动驾驶车辆如何进行传感器标定?

为什么要进行标定&#xff1f;一辆自动驾驶车辆会安装多个传感器&#xff0c;需要通过传感器标定来确定相互之间的坐标关系&#xff0c;从而将多个传感器数据整合为“一个传感器”。因此&#xff0c;准确的传感器标定是实现智能车辆多传感器感知和定位系统的先决条件。传感器标…

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《6》

我们在看Faster R-CNN源码(MXNet版本)的时候&#xff0c;除了下面这些我们遇到的常见的参数解析 import argparse import ast parser argparse.ArgumentParser(descriptionDemonstrate a Faster R-CNN network,formatter_classargparse.ArgumentDefaultsHelpFormatter) parse…

【操作系统系统/Golang】实验5:磁盘调度(FCFS,SSTF,SCAN与循环SCAN)

1 实验问题描述设计程序模拟先来先服务FCFS&#xff0c;最短寻道时间优先SSTF&#xff0c;SCAN和循环SCAN算法&#xff08;对应其他参考书的LOOK和C-LOOK&#xff09;的工作过程。假设有trackNum个磁道号所组成的磁道访问序列&#xff0c;给定开始磁道号initTrackNum和磁头移动…

Java项目管理工具:Maven介绍

Maven 简介下载与环境配置Maven仓库仓库类型本地仓库配置简介 Maven ,一款跨平台的项目管理工具。它主要服务于基于 Java 平台的项目构建与依赖管理。即可以将项目的开发和管理过程抽象成一个项目对象模型(POM),开发人员只需要做一些简单的配置,Maven 便可自动完成项目构建…

HRNet源码阅读笔记(4),庞大的PoseHighResolutionNet模块-stage1

一、图和代码上一讲的图中&#xff0c;有stage1图例如下;关键是看pose_hrnet.py中PoseHighResolutionNet模块的forward函数相关部分如下&#xff1a;def forward(self, x):x self.conv1(x)x self.bn1(x)x self.relu(x)x self.conv2(x)x self.bn2(x)x self.relu(x)x self…

一辈子干好一件事,你就了不起

人生的道路和轨迹&#xff0c;就像是射出去的箭。假如左拐右拐&#xff0c;不但不能射中靶心&#xff0c;达不到目标&#xff0c;还有可能拐弯回到原点&#xff0c;原地踏步。日复一日&#xff0c;年复一年&#xff0c;没有成长和收获&#xff0c;这很可怕。 短暂的2022年&…

设计测试用例的万能公式 + 6大具体方法 = 面试就像聊天?

目录 一、设计测试用例的万能公式 二、设计测试用例的具体方法 2.1、等价类 2.2、边界值 2.3、判定表&#xff08;因果图的另一种形式&#xff09; 2.4、场景设计法 2.5、正交法&#xff08;用的少&#xff0c;基本不可见&#xff09; 2.4.1、使用allparis构建正交表 2.…

算法之动态规划理论

目录 前言 一个模型三个特征理论讲解 1.最优子结构 2.无后效性 3.重复子问题 一个模型三个特征实例剖析 两种动态规划解题思路总结 1.状态转移表法 2.状态转移方程法 四种算法思想比较分析 总结&#xff1a; 参考资料 前言 本篇博文主要讲解动态规划的理论&am…

行业分析| 交通综合执法对讲系统

随着社会的经济发展&#xff0c;人口的增加城市的不断壮大&#xff0c;城市交通情况越来越复杂&#xff0c;交警承担的执法任务越来越重&#xff0c;通信作为交警综合执法对讲调度的重要组成部分&#xff0c;也随之提出了更高的要求。综合执法对讲系统的出现使执法变得高效规范…

【Redis】高级进阶

&#x1f31f;个人博客&#xff1a;www.hellocode.top&#x1f31f; &#x1f31f;Java知识导航&#xff1a;Java-Navigate&#x1f31f; ⭐想获得更好的阅读体验请前往Java-Navigate &#x1f525;本文专栏&#xff1a;《流行框架》 &#x1f31e;如没有JavaWEB基础&#xff0…

【ZooKeeper】第三章 集群搭建

【ZooKeeper】第三章 集群搭建 文章目录【ZooKeeper】第三章 集群搭建一、ZooKeeper 集群介绍1.Leader 选举2.集群角色二、搭建 ZooKeeper 集群1.安装2.配置集群3.启动集群三、故障模拟一、ZooKeeper 集群介绍 1.Leader 选举 Serviceid&#xff1a;服务器 ID 比如有三台服务器…

分享84个NET源码,总有一款适合您

分享84个NET源码&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1r7_yrTfQrg-5whL7AYJiLA?pwdeem6 提取码&#xff1a;eem6 import os from time import sleepimport requests from bs4 import BeautifulSoup from docx import Document from docx.sh…

iOS ReplayKit 屏幕共享,屏幕直播实现

使用replayKit iOS12 之后相关 api 完成系统/app 内 屏幕采集直播视频数据, 采用 socket进行进程间Broadcast Unload Extension 向 宿主 app 传输数据, 后台保活持续采集屏幕数据, 摄像头采集, 数据编码解码 编译环境 Xcode14.2, iOS12 系统屏幕数据采集app 内屏幕共享使用so…