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

基于编译器特性浅析C++程序性能优化

最近在恶补计算机基础知识,学到CSAPP第五章的内容,在这里总结并且展开一下C++程序性能优化相关的内容。

衡量程序性能的方式

一般而言,程序的性能可以用CPE(Cycles Per Element)来衡量,其指的是处理每个元素所需的CPU时钟周期数,计算公式为:CPE = 总执行周期数/处理的元素数量。

计算方式为:

#include <iostream>
#include <chrono>const int N = 1000000;
int arr[N];void test_function() {for (int i = 0; i < N; i++) {arr[i] = i * 2;}
}int main() {auto start = std::chrono::high_resolution_clock::now();test_function();auto end = std::chrono::high_resolution_clock::now();double elapsed_cycles = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() * 2.5; // 假设CPU 2.5 GHzdouble cpe = elapsed_cycles / N; // 计算 CPEstd::cout << "CPE: " << cpe << std::endl;return 0;
}

影响编译器优化的因素

用gcc时,gcc -Og可以指定优化方式,但随着优化等级升高,程序规模也可能增加。

gcc优化等级

  • -O1:不会进行激进优化(如函数内联、代码重排序),不会影响可读性,编译时间仍然较短。优化包括死代码消除、常量传播、循环优化等。
  • -O2:在基本优化的基础上增加更高级优化:消除冗余计算、循环展开、指令调度、函数内联、分支预测优化,仍然不会进行极端优化。
  • -O3:实现更激进的循环展开、自动使用SIMD指令,使函数尽可能内联,并消除冗余加载和存储,对复杂的数学运算进行优化。但可能导致代码膨胀,过度优化会导致性能下降,如缓存效率降低。
  • -Os:基于-O2,但会避免增加代码大小的优化,适合嵌入式系统。

以下为一些妨碍编译器优化的因素:

内存别名使用

对于以下看似相同的代码段:

//代码段1
void twiddle1(long *xp, long *yp){*xp += *yp;*xp += *yp;
}//代码段2
void twiddle2(long *xp, long* yp){*xp += 2* *yp;
}

很显然,代码段2的执行所需耗费时间更短,其需要的内存访问次数更少。

然而,编译器无法将代码1优化为代码2,因为当yp=xp时,代码1等效于xp = 4 xp, 而代码2等效于 *xp = 3 * *xp,编译器不知道函数该如何被调用。这种两个指针可能指向同一个内存位置的情况称为内存别名使用,在只执行安全的优化中,编译器必须假设不同的指针可能会指向内存中同一位置。

修改全局程序状态的函数

对于以下看似相同的代码段:

long counter = 0;
long f(){return counter++;
}
//代码段1
long func1(){return f()+f()+f()+f();
}
//代码段2
long func2(){return 4*f();
}

当函数f的返回值涉及到全局变量counter时,可以看出,func1的输出为6,而func2的输出为0。

将函数定义为内联函数,可以直接将函数调用替换为函数体,例如,代码段1在o1优化下可以展开为:

long funclin(){long t = counter++;t += counter++;t += counter++;t += counter++;return t;
}

如果使用-o2及以上优化,可能会展开为:

long funclin() {long tmp = counter;counter += 4;return tmp + (tmp + 1) + (tmp + 2) + (tmp + 3);
}

直接优化方法

为了举例说明优化方法是如何实现的,我们定义向量数据结构如下:

typedef struct{long len;data_t *data;
} vec_rec, *vec_ptr;

data_t代表基本元素的数据类型。

定义初始化该向量、访问向量元素以及获取向量长度的方法如下:

/* Create vector of specified length */
vec_ptr new_vec(long len)
{/* Allocate header structure */vec_ptr result = (vec_ptr) malloc(sizeof(vec_rec));data_t *data = NULL;if (!result)return NULL;  /* Couldn't allocate storage */result->len = len;/* Allocate array */if (len > 0) {data = (data_t *)calloc(len, sizeof(data_t));if (!data) {free((void *) result);return NULL; /* Couldn't allocate storage */}}/* Data will either be NULL or allocated array */result->data = data;return result;
}/** Retrieve vector element and store at dest.* Return 0 (out of bounds) or 1 (successful)*/
int get_vec_element(vec_ptr v, long index, data_t *dest)
{if (index < 0 || index >= v->len)return 0;*dest = v->data[index];return 1;
}/* Return length of vector */
long vec_length(vec_ptr v)
{return v->len;
}

采用计算向量元素乘积的初始代码如下:

#define IDENT 1
#define OP *
/* Implementation with maximum use of data abstraction */
void combine1(vec_ptr v, data_t *dest)
{long i;*dest = IDENT;for (i = 0; i < vec_length(v); i++) {data_t val;get_vec_element(v, i, &val);*dest = *dest OP val;}
}

对于这段初始代码,有一些方向可以进行优化改进。

提高循环效率

代码移动

代码移动指的是将在循环里需要执行多次但计算结果不会改变的计算移动到循环外:

#define IDENT 1
#define OP *
/* Implementation with maximum use of data abstraction */
void combine2(vec_ptr v, data_t *dest)
{long i;long length = vec_length(v);*dest = IDENT;for (i = 0; i < length; i++) {data_t val;get_vec_element(v, i, &val);*dest = *dest OP val;}
}

减少过程调用

上述函数可以继续简化为:

data_t *get_vec_start(vec_ptr v)
{return v->data;
}/* Direct access to vector data */
void combine3(vec_ptr v, data_t *dest)
{long i;long length = vec_length(v);data_t *data = get_vec_start(v);*dest = IDENT;for (i = 0; i < length; i++) {*dest = *dest OP data[i];}
}

这种写法和combine2相比,减少了索引与数组边界的比较,但优化效果并不明显。

消除不必要的内存引用

对于combine3的赋值过程:

*dest = *dest OP data[i];

需要访问*dest指针的值,再根据这个地址从内存中取dest数组的值,并在计算完成后赋值到对应的内存上,在每次迭代过程中都要完成这样一个从内存读写数据的过程,将函数继续简化,减少对内存的读写:

void combine4(vec_ptr v, data_t *dest)
{long i;long length = vec_length(v);data_t *data = get_vec_start(v);data_t cur = IDENT;for (i = 0; i < length; i++) {cur = cur OP data[i];}*data = cur;
}

考虑机器特性的优化方法

上述优化方法都没有依赖目标机器的任何特性,如果要进一步提升性能,则需要考虑利用处理器微体系结构进行优化。

现代处理器结构

现代微处理器的简化示意图如下图所示,其可以分为指令控制单元ICU和执行单元EU两部分。

在这里插入图片描述

  • 取指控制:ICU从指令高速缓存中读取指令,并在译码后将对应的操作发送到EU。一般来说,会在当前执行的指令很早之前就进行取指。然而当程序遇到分支时,处理器采用分支预测技术,会猜测是否选择该分支并预测其目标地址。使用投机执行技术,处理器会在确定分支预测是否正确前就跳到分支对应的指令,甚至开始执行这些对应的操作。如果分支预测错误,则将状态重新设为分支点的状态。
  • 指令译码:接收实际的程序指令并将其转换为一组基本操作。
  • 加载和存储单元:内置加法器,用于读写内存。
  • 分支单元:向ICU返回分支预测是否正确的结果。
  • 算术运算单元:执行整数和浮点数操作的不同组合。
  • 退役单元:记录正在进行的处理,并确保其遵守机器级程序的语义。退役单元包含了多种寄存器,并控制这些寄存器的更新。指令译码时,其信息被放置在一个队列中,直到分支点预测结果出现,若预测正确,则程序寄存器的更新将被实际执行。任何对程序寄存器的更新都只会在指令退役的时候才会发生。

功能单元的性能

对于功能单元进行运算的性能,有以下几个指标可以用来衡量:

延迟L:表示完成运算所需要的总时间

发射时间I:表示两个连续的同类型运算之间需要的最小周期数

容量C:表示能够执行该运算的功能单元的数量

操作的吞吐量=C/I

对于一个执行n个乘法的函数,若其需要L*n+K个周期,其中K为调用函数和初始化等开销,此时CPE=L,对于单个按照顺序执行的功能单元组成的函数,延迟L表明了CPE的最小值,而对于多个功能单元组成的函数,还需要考虑其吞吐量。

处理器操作的抽象模型

将函数combine4的循环部分转换为汇编代码:

Inner loop of combine44. data_t = double, OP = *
acc in %xmm0, data+i in %rdx, data+length in %rax
1 .L25:
2 vmulsd (%rdx), %xmm0, %xmm0    loop: Multiply acc by data[i]
3 addq $8, %rdx                  Increment data+i
4 cmpq %rax, %rdx                Compare to data+length
5 jne .L25                       If !=, goto loop

将其抽象为数据流图,并去除不影响数据流的指令:

在这里插入图片描述

可以看出,乘法和加法运算是制约循环性能的两个因素,而浮点乘法的延迟约为整数加法的5倍,其成为了最关键的制约原因,程序的CPE为5。循环中的其他操作与乘法器并行地执行。

循环展开

循环展开是一种程序变换,通过增加每次迭代计算元素的数量来减少循环的迭代次数。

其优点为,可以提高缓存命中率,增加循环体内语句并发执行的可能性,同时减少分支预测失败的可能性。

用循环展开继续改进上述代码为:

/* 2 x 1 loop unrolling */
void combine5(vec_ptr v, data_t *dest)
{long i;long length = vec_length(v);long limit = length - 1;data_t *data = get_vec_start(v);data_t cur= IDENT;/* Combine 2 elements at a time */for (i = 0; i < limit; i += 2) {cur= (cur OP data[i]) OP data[i + 1];}/* Finish any remaining elements */for (; i < length; i++) {cur =  cur OP data[i];}*dest = cur;
}

编译器可以很轻松地执行循环展开,用GCC的优化等级大于等于3时就会执行循环展开。

提高并行性

我们知道,乘法操作和加法操作是可以并行化的,也就是说,不需要等待对方完成即可进行下一次操作,可以在每个时钟周期就开始一次新的操作。但目前的代码还并不能更高速率地执行乘法和加法,这是因为我们将累积值放在一个单独的变量cur中,在前面计算完成之前都不能计算cur的新值。

为了提高并行性,我们可以用多个累积变量分别计算:

void combine6(vec_ptr v, data_t *dest){long i;long length = vec_length(v);long limit = length - 1;data_t cur0 = IDNET;data_t cur1 = IDNET;for(i = 0; i <limit; i+=2){cur0 = cur0 OP data[i];cur1 = cur1 OP data[i+1];}for(; i < length; i++)cur0 = cur0 OP data[i];*dest = cur0 OP cur1;
}

我们可以将多个累积变量变换归纳为将循环展开k次,以及并行累积k个值,得到k×k的循环展开,当k足够大时,程序在所有情况下几乎都能达到吞吐量界限。通常,只有保持能执行该操作的所有功能单元的流水线都是满的,程序才能达到这个操作的吞吐量界限,对延迟为L,容量为C的操作而言,要求循环展开因子k ≥ L*C即可达到最大吞吐量。

除了以上并行累计的方式以外,还可以通过重新结合变换的方式对combine5进行继续优化:

void combine7(vec_ptr v, data_t *dest){long i;long length = vec_length(v);long limit = length-1;data_t *data = get_vec_start(v);data_t cur = IDENT;for(i = 0; i < limit; i+=2){cur = cur OP (data[i] OP data{i+1]);}for(; i < length; i++)cur = cur OP data[i];*dest = cur;
}

combine7和combine5的区别在于**data[i] OP data[i+1]**计算的先后顺序不同,而(data[i] OP data[i+1])时可以被并行计算的,因为它不依赖于cur的计算结果,可以提前计算。(现代CPU的超标量架构,可以在一个时钟周期内执行多个独立的指令,如果两个指令没有数据依赖,CPU可以同时执行它们。)

书写适用于条件传送的代码

条件传送(Conditional Move, CMOV) 是一种 CPU 指令优化技术,它允许根据条件决定是否执行数据传送而不使用传统的条件跳转(branching)
在 x86 架构中,CMOV 指令集(如 CMOVZ, CMOVNZ, CMOVL 等)可以在满足某些条件时,将值从一个寄存器传送到另一个寄存器,而不会触发分支预测失败的问题。

在 C++ 中,我们可以使用 条件运算符(?:内联汇编(asm标准库函数(std::max 以及 SIMD 指令 来实现 条件传送。

在现代C++编译器中,使用三元运算符可能被编译器优化为CMOV指令:

#include <iostream>//传统条件分支的代码
int branching(int x, int y){if (x > y)return x;elsereturn y;}
//使用条件传送的代码
int conditional_move(int x, int y) {return (x > y) ? x : y;  // 编译器可能优化为 CMOV
}int main() {int a = 5, b = 10;std::cout << "Max: " << conditional_move(a, b) << std::endl;return 0;
}

除此之外,gcc在 -O2 或更高级别优化下,std::max(a, b) 可能会被优化为 CMOV 指令

相关文章:

基于编译器特性浅析C++程序性能优化

最近在恶补计算机基础知识&#xff0c;学到CSAPP第五章的内容&#xff0c;在这里总结并且展开一下C程序性能优化相关的内容。 衡量程序性能的方式 一般而言&#xff0c;程序的性能可以用CPE&#xff08;Cycles Per Element&#xff09;来衡量&#xff0c;其指的是处理每个元素…...

在 Docker 中搭建GBase 8s主备集群环境

本文介绍了如何在同一台机器上使用 Docker 容器搭建GBase 8s主备集群环境。 拉取镜像 拉取GBase 8s的最新镜像 docker pull liaosnet/gbase8s或者docker pull liaosnet/gbase8s:v8.8_3513x25_csdk_x64注&#xff1a;在tag为v8.8_3513x25_csdk_x64及之后的版本中&#xff0c;…...

hadoop集群环境配置

目录 VMware虚拟机安装 Xshell安装 网络问题 centos7下载 ---------参考以下视频步骤进行生态搭建---------- 搭建好hadoop01 克隆出hadoop02、hadoop03 启动三台虚拟机 打开终端 输入 记录下各个ip 打开Xshell&#xff0c;新建会话 修改主机名 配置静态IP 主机名称…...

Hive-优化(参数优化篇)

map 数和reduce数 控制hive任务中的map数 合适的map数&#xff0c;会让资源分配的更平均&#xff0c;让我们的代码运行更快&#xff0c;通常情况下&#xff0c;作业会通过input的目录产生一个或者多个map任务。我们可以通过调整参数来控制运行过程中的map数。 Hive Map的数量…...

深度学习|MAE技术全景图:自监督学习的“掩码魔法“如何重塑AI基础

一、引言&#xff1a;深度学习的困境与自监督的曙光 深度学习&#xff08;Deep Learning&#xff09;无疑是当今人工智能领域基础中的基础。从图像识别到自然语言处理&#xff08;NLP&#xff09;&#xff0c;它在无数任务中展现了卓越性能。例如&#xff0c;在安防监控中&…...

学习threejs,使用LineBasicMaterial基础线材质

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.LineBasicMaterial1.…...

第本章:go 切片

注意&#xff1a; 切片必须要初始化 才能使用 &#xff0c;切片是引用类型 a :[]int{} // 这上叫始化 此时并没有申请内存 // 如果要追加值的话&#xff1a; append ints : append(a, 1, 2, 3)a : make([]int,5) // 声明切片类型var a []string //声明一…...

dify + ollama + deepseek-r1+ stable-diffusion 构建绘画智能体

故事背景 stable-diffusion 集成进 dify 后&#xff0c;我们搭建一个小智能体&#xff0c;验证下文生图功能 业务流程 #mermaid-svg-6nSwwp69eMizP6bt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6nSwwp69eMiz…...

Java基础面试题全集

1. Java语言基础 1.1 Java是什么&#xff1f; • Java是一种广泛使用的编程语言&#xff0c;最初由Sun Microsystems&#xff08;现为Oracle公司的一部分&#xff09;于1995年发布。它是一种面向对象的、基于类的、通用型的编程语言&#xff0c;旨在让应用程序“编写一次&…...

基于multisim的自动干手器设计与仿真

1 设计的任务与要求 设计一个输出 5V 的直流稳压电源。用开关的闭合模拟手挡住光线的功能。用灯的亮灭模拟烘干吹风功能。 2 方案论证与选择 2.1 自动干手器的系统方案 本设计由5V直流电源、红外发射电路、红外接收电路、灯模拟电路构成。 1. 5V直流电源系统 这一部分是整…...

three.js 在 webGL 添加纹理

在我们生成了3D设计之后&#xff0c;我们可以添加纹理使其更加吸引人。在 webGL 和 p5.js中&#xff0c;可以使用 gl.texImage2D() 和 texture() API来为形状应用纹理。 使用 webGL 在 webGL 中&#xff0c;gl.texImage2D() 函数用于从图像文件生成2D纹理。该函数接受许多参…...

Docker 部署 MongoDB 并持久化数据

Docker 部署 MongoDB 并持久化数据 在现代开发中&#xff0c;MongoDB 作为 NoSQL 数据库广泛应用&#xff0c;而 Docker 则提供了高效的容器化方案。本教程将介绍如何使用 Docker 快速部署 MongoDB&#xff0c;并实现数据持久化&#xff0c;确保数据不会因容器重启或删除而丢失…...

SpringBoot优雅关机,监听关机事件,docker配置

Spring Boot 提供了多种方法来实现优雅停机&#xff08;Graceful Shutdown&#xff09;&#xff0c;这意味着在关闭应用程序之前&#xff0c;它会等待当前正在处理的请求完成&#xff0c;并且不再接受新的请求。 一、优雅停机的基本概念 优雅停机的主要步骤如下&#xff1a; …...

网络基础(一)【网络发展/认识协议/网络 VS 系统/以太网通信原理/重谈协议/网络中的地址管理】

网络基础&#xff08;一&#xff09; 1. 网络的发展2. 认识协议3. 网络 VS 系统4. 以太网通信原理5. 重谈协议6. 网络中的地址管理 1. 网络的发展 最开始时&#xff0c;计算机之间相互独立。 但是为了协作完成一些任务&#xff0c;就产生了计算机之间相互通讯的需求&#xff0c…...

PostgreSQL、SQL Server和MySQL数据库性能调优与故障排除技术

通过结合具体技术特性与工具链的深度使用&#xff0c;可系统化提升数据库性能和稳定性。建议根据实际负载特征制定监控-分析-优化的闭环管理流程。 数据库技术&#xff1a; PostgreSQL 13&#xff1a;逻辑复制、分区表、并行查询、监控工具&#xff08;如pg_stat_statements、…...

本地YARN集群部署

请先完成HDFS的前置部署&#xff0c;部署方式可查看:本地部署HDFS集群https://blog.csdn.net/m0_73641796/article/details/145998092?spm1001.2014.3001.5502 部署说明 组件配置文件启动进程备注Hadoop HDFS需修改 需启动: NameNode作为主节点 DataNode作为从节点 Secondary…...

Redis数据结构——list

目录 列表命令 lpush lrange lpushx rpush rpushx lpop rpop lindex linsert llen lrem ltrim lset blpop / brpop 命令总结 编码方式 list相当于数组或者顺序表,但并不是简单的数组&#xff0c;更接近于C中的"双端队列"(deque)。 最左侧的下标…...

World of Warcraft [CLASSIC] BigFoot BiaoGe

World of Warcraft [CLASSIC] BigFoot BiaoGe 金团表格插件 设置60秒拍卖装备时间 ALT 鼠标左键&#xff0c;点击装备&#xff0c;弹出对话框&#xff0c;填写 1&#xff09;拍卖时间默认60秒&#xff0c;起拍价&#xff0c; 2&#xff09;点击【开始拍卖】 团队所有安装了…...

CentOS Docker 安装指南

CentOS Docker 安装指南 引言 Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。Docker 容器是完全使用沙箱机制&#xff0c;相互之…...

PHP:phpstudy无法启动MySQL服务问题解决

文章目录 一、问题说明二、解决问题 一、问题说明 我的Windows10系统&#xff0c;之前安装过MySQL5.7的版本。 然后&#xff0c;用phpstudy安装MySQL8&#xff0c;并启动MySQL8。 发生无法启动的情况。 二、解决问题 1、删除本地MySQL7的服务 net stop MySQL //这里的服务名…...

【电控笔记z29】扰动估测器DOB估测惯量J-摩擦系数B

基本原理 扰动估测器的核心思想是通过向电机系统施加特定的扰动信号&#xff0c;观察系统响应的变化&#xff0c;然后利用系统的动态模型和控制理论来估计未知参数&#xff0c;如惯量和摩擦系数 。一般基于电机的运动方程建立数学模型&#xff0c;结合观测到的电机实际运行数据…...

STM32-I2C通信外设

目录 一&#xff1a;I2C外设简介 二&#xff1a;I2C外设数据收发 三&#xff1a;I2C的复用端口 四&#xff1a;主机发送和接收 五&#xff1a;硬件I2C读写MPU6050 相关函数&#xff1a; 1.I2C_ GenerateSTART 2.I2C_ GenerateSTOP 3.I2C_ AcknowledgeConfig 4.I2C…...

计算机二级MS之PPT

声明&#xff1a;跟着大猫和小黑学习随便记下一些笔记供大家参考&#xff0c;二级考试之前将持续更新&#xff0c;希望大家二级都能轻轻松松过啦&#xff0c;过了二级的大神也可以在评论区留言给点建议&#xff0c;感谢大家&#xff01;&#xff01; 文章目录 考题难点1cm25px…...

Spring Boot 3 整合 MinIO 实现分布式文件存储

引言 文件存储已成为一个做任何应用都不可回避的需求。传统的单机文件存储方案在面对大规模数据和高并发访问时往往力不从心&#xff0c;而分布式文件存储系统则提供了更好的解决方案。本篇文章我将基于Spring Boot 3 为大家讲解如何基于MinIO来实现分布式文件存储。 分布式存…...

C++ Primer 交换操作

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

分布式中间件:Redis介绍

目录 Redis 概述 Redis 的特点 高性能 丰富的数据结构 持久化 分布式特性 简单易用 Redis 的数据结构 字符串&#xff08;String&#xff09; 哈希&#xff08;Hash&#xff09; 列表&#xff08;List&#xff09; 集合&#xff08;Set&#xff09; 有序集合&…...

软件测试的基础入门(二)

文章目录 一、软件&#xff08;开发&#xff09;的生命周期什么是生命周期软件&#xff08;开发&#xff09;的生命周期需求分析计划设计编码测试运行维护 二、常见的开发模型瀑布模型流程优点缺点适应的场景 螺旋模型流程优点缺点适应的场景 增量模型和迭代模型流程适应的场景…...

学之思社区版考试系统docker-compose部署

参考 开源项目-Docker部署学之思管理系统 安装docker sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Bas…...

深度优先搜索(DFS)和广度优先搜索(BFS)——c#实现

一、深度优先搜索&#xff08;DFS&#xff09; 原理&#xff1a; 沿着分支尽可能深入&#xff0c;直到到达叶子节点&#xff0c;然后回溯探索其他分支 类似走迷宫时优先选择一条路走到黑&#xff0c;碰壁再回退 数据结构&#xff1a;栈&#xff08;Stack&#xff09;或递归实…...

什么是hive

Apache Hive 是一个基于 Hadoop 生态系统构建的数据仓库工具&#xff0c;主要用于处理和分析大规模的结构化数据。它允许用户通过类似 SQL 的查询语言&#xff08;HiveQL&#xff09;进行数据操作&#xff0c;而无需直接编写复杂的 MapReduce 程序。以下是 Hive 的核心特点和应…...

JVM详解

目录 一.JVM的概念 1. 什么是JVM? 2.JVM用来干什么? 二JVM运行流程 JVM执⾏流程 2.1类加载机制 2.2类加载机制带来了哪些好处? 2.3类加载的过程是什么? 2.3.1加载 2.3.2验证 2.3.3准备阶段 2.3.4解析阶段 符号引⽤ 直接引⽤ 2.3.5初始化阶段 2.4类加载器 什么…...

PCA(主成分分析)核心原理

一、PCA&#xff08;主成分分析&#xff09;核心原理 即主成分分析技术&#xff0c;又称主分量分析技术&#xff0c;旨在利用降维的思想&#xff0c;把多指标转化为少数几个综合指标。在统计学中&#xff0c;主成分分析PCA是一种简化数据集的技术。它是一个线性变换。这个变换…...

DeepSeek私有化部署6:openEuler 24.03-LTS-SP1安装Open WebUI

Open WebUI是一个 Open WebUI 是一个可扩展的、功能丰富、用户友好的自托管 AI 平台&#xff0c;专为完全离线运行而设计。 它支持多种 LLM 运行环境&#xff0c;包括 Ollama 和 OpenAI 兼容的 API&#xff0c;并内置了用于 RAG 的推理引擎&#xff0c;是一个强大的 AI 部署解决…...

【一文学会 HTML5】

目录 HTML概述基本概念HTML 发展历程HTML 基本结构 网页基本标签标题标签&#xff08;<h1> - <h6>&#xff09;段落标签&#xff08;<p>&#xff09;换行标签&#xff08;<br>&#xff09;水平线标签&#xff08;<hr>&#xff09;注释&#xff0…...

前端题目类型

HTMLCSS常见面试题 HTML标签有哪些行内元素 img、picture、span、input、textarea、select、label 说说你对元素语义化的理解 元素语义化就是用正确的元素做正确的事情。虽然理论上所有html元素都可通过css样式实现相同效果&#xff0c;但这样会使事情复杂化&#xff0c;所以需…...

nodejs学习——nodejs和npm安装与系统环境变量配置及国内加速

nodejs和npm安装与系统环境变量配置及国内加速 下载node-v22.14.0-x64.msi 建议修改为非C盘文件夹 其它步骤&#xff0c;下一步&#xff0c;下一步&#xff0c;完成。 打开CMD窗口查看安装详情 $ node -v v22.14.0 $ npm -v 10.9.2$ npm config list创建node_global和node_c…...

[视频编码]rkmpp 实现硬件编码

mpi_enc_test的命令参数描述说明 命令参数的描述说明如下&#xff1a; 命令参数 描述说明 -i 输入的图像文件。 -o 输出的码流文件。 -w 图像宽度&#xff0c;单位为像素。 -h 图像高度&#xff0c;单位为像素。 -hstride 垂直方向相邻两行之间的距离&#xff0c;单…...

Vue3实战学习(Vue3的基础语法学习与使用(超详细))(3)

目录 &#xff08;1&#xff09;Vue3工程环境准备、项目基础脚手架搭建详细教程。(博客链接) &#xff08;2&#xff09;Vue3的基础语法学习与使用。 &#xff08;1&#xff09;"{{}}"绑定数据。 <1>ref()函数定义变量——绑定数据。 <2>reactive({...})…...

基于multisim的花样彩灯循环控制电路设计与仿真

1 课程设计的任务与要求 &#xff08;一&#xff09;、设计内容&#xff1a; 设计一个8路移存型彩灯控制器&#xff0c;基本要求&#xff1a; 1. 8路彩灯能演示至少三种花型&#xff08;花型自拟&#xff09;&#xff1b; 2. 彩灯用发光二极管LED模拟&#xff1b; 3. 选做…...

EasyRTC嵌入式视频通话SDK的跨平台适配,构建web浏览器、Linux、ARM、安卓等终端的低延迟音视频通信

1、技术背景 WebRTC是一项开源项目&#xff0c;旨在通过简单的API为浏览器和移动应用程序提供实时通信&#xff08;RTC&#xff09;功能。它允许在无需安装插件或软件的情况下&#xff0c;实现点对点的音频、视频和数据传输。 WebRTC由三个核心组件构成&#xff1a; GetUserM…...

【CSS】gap 属性详解

文章目录 一、什么是 gap 属性1. 定义2. 语法3. 默认值 二、gap 属性的基本用法1. 网格布局中的应用2. 弹性布局中的应用3. 单值和双值的区别 三、gap 属性的实际应用场景1. 表单布局优化2. 图片网格布局 四、gap 的注意事项1. 浏览器兼容性2. 替代 margin 的场景3. 不同布局的…...

【招聘精英】

我们公司是一个位于石家庄的一个科技型新型技术公司。主要做人力资源、用工、科技等方面。 有意向回石家庄的或者已经在石家庄的技术大咖、软件大牛、产品大佬、UI大神可以来了解一下。 现在招聘 高级前端开发 高级java开发 其他岗位也可以联系。 有意向的朋友可以私信我。 -…...

qt 操作多个sqlite文件

qt 操作多个sqlite文件 Chapter1 qt 操作多个sqlite文件1. 引入必要的头文件2. 创建并连接多个SQLite数据库3. 代码说明4. 注意事项 Chapter2 qt 多线程操作sqlite多文件1. 引入必要的头文件2. 创建数据库操作的工作线程类3. 在主线程中创建并启动多个工作线程4. 代码说明5. 运…...

【自学笔记】Numpy基础知识点总览-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Numpy基础知识点总览目录1. 简介Numpy是什么为什么使用Numpy 2. 数组对象&#xff08;ndarray&#xff09;创建数组数组的属性数组的形状操作 3. 数组的基本操作数组…...

DP 问题 -- LQR中的DP问题

深入地介绍线性二次调节问题&#xff08;Linear Quadratic Regulator, LQR&#xff09;&#xff0c;并详细说明它作为动态规划&#xff08;DP&#xff09;的一个经典应用问题的求解过程。 &#x1f4cc; 一、LQR问题定义&#xff08;最优控制视角&#xff09; LQR 问题是一种特…...

Win7重装不翻车!ISO镜像安全下载渠道+BIOS设置避雷手册

一、写在前面&#xff1a;为什么你需要这份教程&#xff1f; 当电脑频繁蓝屏、系统崩溃甚至无法开机时&#xff0c;重装系统可能是最后的救命稻草。但市面上的教程往往存在三大痛点&#xff1a; ⚠️ 镜像来源不明导致系统被植入后门 ⚠️ 启动盘制作失败反复折腾 ⚠️ 操作失…...

CEF在MFC上的示例工程

CEF 在 MFC 中的使用 工程配置 1、首先创建一个MFC对话框工程 创建完运行测试效果如下 2、MFC工程引入CEF库 将 CEF 目录下的 cef子目录下载解压后放到MFC工程中&#xff1a; 然后在VS中对工程右键 -> 属性 -> C/C -> 常规 -> 附加包含目录&#xff0c;添加“.\…...

#UVM# 关于 config_db 机制中的直线非直线设置和获取讲解

在 UVM 验证环境中,uvm_config_db 是一种强大的机制,用于在不同组件之间传递配置参数。实际应用中,我们经常使用直线和非直线的设置与获取。今天,着重回忆一下这些内容,希望实际中更加方便的使用。 UVM 树结构示例 假设 UVM 树结构如下: uvm_test_top ├── env │ …...

[PWNME 2025] PWN 复现

这种比赛得0也不容易&#xff0c;前边暖声还是能作的。 GOT 指针前溢出&#xff0c;可以溢出到GOT表&#xff0c;然后把后门写上就行 Einstein 这个拿到WP也没复现成&#xff0c;最后自己改了一下。 int __cdecl handle() {int offset; // [rsp8h] [rbp-38h] BYREFunsigne…...

Java网络编程,多线程,IO流综合项目一一ChatBoxes

Java网络编程&#xff0c;多线程&#xff0c;IO流综合小项目一一ChatBoxes 作者&#xff1a;blue 时间&#xff1a;2025.3.7 文章目录 Java网络编程&#xff0c;多线程&#xff0c;IO流综合小项目一一ChatBoxes1.项目介绍2.项目源码剖析2.1客户端源码2.2客户端Sender线程Runn…...