Linux错误(2)程序触发SIGBUS信号分析
Linux错误(2)之SIGBUS错误分析
Author: Once Day Date: 2025年3月12日
一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…
漫漫长路,有人对你微笑过嘛…
全系列文章可参考专栏: Linux实践记录_Once_day的博客-CSDN博客
参考文章:
- libunwind] Unwind through aarch64/Linux sigreturn frame (llvm.org)
- Aarch64 crash (SIGBUS) due to atomic instructions on under-aligned memory (gnu.org)
- Arm A64 Instruction Set Architecture
- JVM coredump分析系列(4):常见的SIGBUS案例分析 | HeapDump性能社区
- Logging and debugging unaligned accesses on Linux / aarch64 - Stack Overflow
- singal 7 SIGBUS(Bus error)_program received signal sigbus, bus error. memset
-CSDN博客- Bus error的调试解决方法-CSDN博客
- 段错误(SIGSEGV)与总线错误(SIGBUS)-CSDN博客
- SIGSEGV 和 SIGBUS & gdb看汇编 - blcblc - 博客园 (cnblogs.com)
- c - What is a bus error? Is it different from a segmentation fault? - Stack Overflow
- X86 Linux 下 SIGBUS 总结 - twoon - 博客园 (cnblogs.com)
- 关于SIGBUS 信号_received signal sigbus, bus error-CSDN博客
- access_mem in aaarch64 coredump · Issue #260 · libunwind/libunwind · GitHub
- libunwind(3) (nongnu.org)
文章目录
- Linux错误(2)之SIGBUS错误分析
- 1. 问题分析
- 1.1【现象介绍】
- 1.2【分析原因】
- 1.3【解决思路】
- 2. 实例验证
- 2.1 对齐问题触发SIGBUS信号
- 2.2 映射内存大小改变触发SIGBUS信号
- 3. 总结
1. 问题分析
1.1【现象介绍】
SIGBUS是BUS error的缩写,中文称为总线错误信号。它是Unix/Linux系统中的一种异常信号,通常在访问内存时发生某些类型的错误时产生。产生SIGBUS的典型原因包括:
- 地址对齐错误(Alignment Fault):当访问的内存地址不满足硬件的对齐要求时触发。例如在需要4字节对齐的系统上访问一个地址不是4的倍数的int变量。
- 未映射的物理地址访问:试图访问未映射到任何设备的物理地址空间时会触发SIGBUS。这可能是由错误的指针运算或直接访问物理内存导致的。
- 特定于设备的硬件错误:一些硬件相关的错误,如访问未初始化的内存控制器、总线奇偶校验错误等也会触发SIGBUS。
SIGBUS在不同的硬件架构和字长下会有一些差异:
- X86架构:在x86上,SIGBUS主要出现在对齐错误的情况下。x86 CPU允许未对齐的内存访问,但通常会有性能损失。只有使用了SIMD指令(如SSE)时要求更严格的对齐,否则会产生SIGBUS。
- ARM架构:相比x86,ARM CPU通常要求更严格的内存对齐,未对齐访问会直接触发SIGBUS而不只是性能问题。尤其是在ARM64上,对齐要求更高。
- 大/小端序:在一些场景下,访问不同字节序的数据也可能触发SIGBUS。但这个问题通常在编译器层面处理。
SIGBUS和SIGSEGV(Segmentation Fault,段错误)信号有一些相似之处,它们都和非法内存访问有关,有时会被混淆。它们主要区别在于:
-
产生原因:SIGSEGV由访问未映射或者权限不足的虚拟内存地址触发,而SIGBUS则主要由访问映射的物理内存但其他硬件相关错误触发。
-
处理难度:SIGSEGV相对容易判断和修复,通常检查程序的地址映射即可。而SIGBUS可能和具体硬件相关,排查难度大一些。
-
可恢复性:SIGSEGV异常通过修改地址映射表可以在一定程度上恢复执行,而SIGBUS异常通常不可恢复,因为可能对应着物理硬件错误。
需要注意SIGBUS更多的和硬件体系结构相关,不同系统和编译器下可能有细微差异。在编写底层程序时,彻底了解目标平台的内存模型和对齐要求是很有必要的。
现代CPU一般不会因为地址非对齐出现SIGBUS错误,更常见原因是映射的内存地址出现了问题,如SO库被更新、共享内存大小变化、映射的页面属性异常等。
1.2【分析原因】
SIGBUS触发场景常见有如下两种:
(1)文件映射访问异常:进程通过mmap系统调用将文件映射到内存中,建立文件和内存页面之间的映射关系。这种方式可以实现高效的文件IO,避免了繁琐的read/write系统调用。然而,这种映射是基于文件大小的,如果文件大小发生变化,已经映射的内存页面可能会出现问题。
如果进程A对文件进行了mmap,而此时另一个进程B对该文件进行了truncate操作,将文件截断到更小的大小。这时,进程A中已经映射的超出文件实际大小的那部分内存页就处于一种不一致的状态。当进程A试图访问这些无效的内存页时,就会触发SIGBUS信号。
另一个常见场景是,某个进程直接用一个新文件覆盖了旧的动态库或可执行文件。由于系统出于性能考虑,通常采用copy-on-write的策略,并不会立即使已经加载的旧版本失效。只有当进程真正执行到新文件中不存在的部分(例如新版本删减了一些代码)时,才会触发SIGBUS。这种场景在升级更新软件时容易遇到。
(2)访问不对齐的内存:现代处理器对内存的访问通常要求地址按照特定的字节数对齐,例如32位的整数要求地址是4的倍数,64位的整数要求地址是8的倍数。这种要求和硬件的设计有关,可以简化电路并提高访问效率。
在x86平台上,CPU一般允许访问未对齐的内存,但会带来一定的性能损失。而在ARM等RISC架构的处理器上,未对齐访问通常会直接触发异常(ARM64位CPU会自行处理对齐问题,一般不会触发异常)。程序员在编写代码时,尤其是在处理网络数据或磁盘数据时,需要特别注意字节对齐问题。
有趣的是,x86平台也提供了一种机制,可以主动禁止未对齐访问,即通过修改EFLAGS寄存器的AC(Alignment Check)标志位。当设置AC位为1时,CPU会在每次内存访问时检查地址的对齐情况,如果发现未对齐访问就会抛出SIGBUS异常。
这个特性对于调试和测试代码很有帮助。它可以帮助程序员及早发现代码中隐藏的对齐问题,提高软件的可移植性和稳定性。但在生产环境中一般不会启用这个特性,因为它会带来额外的性能开销。
1.3【解决思路】
(1)文件映射访问异常的解决方案:这类问题的根源在于多个进程对同一个文件进行了不同步的操作。因此,解决方案的核心思路是加强进程间的协调和同步。具体可以采取以下措施:
-
文件锁:在对文件进行映射或者修改大小之前,先获取文件锁。这样可以防止其他进程同时修改文件,导致不一致。Linux提供了flock和fcntl两种文件锁机制,可以根据需要选用。
-
避免直接覆盖文件:如果需要更新动态库或可执行文件,不要直接用新文件覆盖旧文件,而是先写入一个新文件,然后用rename系统调用进行原子性的替换。这样可以确保任何时刻文件系统中只存在一个完整的版本。
-
异常处理:在访问mmap的内存时,用try/catch等机制捕获SIGBUS异常,并进行适当的错误处理,如重新加载文件、通知用户等,提高程序的健壮性。
-
定期检查文件大小:如果进程长时间持有一个mmap,可以定期检查文件的实际大小是否发生变化,如果变小了就及时解除不一致的映射,重新进行mmap。
(2)访问不对齐内存的解决方案:对于这类问题,首要原则是尽量避免在代码中产生非对齐访问。具体措施包括:
-
使用对齐的数据结构:在定义结构体时,确保每个字段都按照其大小要求进行对齐。可以使用编译器提供的对齐属性,如GNU C的
__attribute__((aligned(n)))。 -
内存分配时考虑对齐:使用malloc、mmap等分配内存时,确保返回的内存地址是对齐的。可以使用posix_memalign、aligned_alloc等对齐版本的内存分配函数。
-
网络/磁盘IO时注意对齐:在处理网络数据或磁盘数据时,注意数据的边界可能不对齐。需要使用memcpy等函数进行中间缓冲,不要直接将IO缓冲区强制转换为结构体指针。
-
使用对齐版本的内存访问指令:现代CPU提供了一些对齐版本的内存访问指令,如movaps、lddqu等。在进行大块数据操作时,使用这些指令可以避免对齐异常。
-
必要时进行填充:如果某些数据结构无法完美对齐,可以在末尾添加填充字节,使其对齐。虽然这会浪费一些内存空间,但可以避免更严重的异常。
2. 实例验证
2.1 对齐问题触发SIGBUS信号
测试代码如下:
/** SPDX-License-Identifier: BSD-3-Clause** Copyright (c) 2025 Once Day <once_day@qq.com>, All rights reserved.** @FilePath: /tools/sigbus_alignment.c* @Author: Once Day <once_day@qq.com>.* @Date: 2025-03-17 21:42* @info: Encoder=utf-8,Tabsize=4,Eol=\n.** @Description:* 测试SIGBUS信号**/#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>unsigned long int original_eflags;
int temp_value;void sigbus_handler(int sig)
{printf("Caught SIGBUS: Alignment Fault!\n");// 恢复原始的EFLAGS值__asm__ volatile("push %0 \n\t popf" : : "r"(original_eflags));exit(1);
}int main()
{// 安装SIGBUS信号处理器signal(SIGBUS, sigbus_handler);// 分配一个字符数组(确保未对齐)char data[64] = {0};// 将字符数组的起始地址+3转换为int指针int *misaligned = (int *)((((uint64_t)(data + 8)) & ~0x7) + 1);// 手动设置CPU对齐检查标识__asm__ volatile("pushf \n\t pop %0" : "=r"(original_eflags));// 打印原始EFLAGS值printf("Original EFLAGS: 0x%lx\n", original_eflags);// 打印对齐检查位printf("Alignment Check Bit: %s\n", (original_eflags & 0x40000) ? "Enabled" : "Disabled");printf("Misaligned pointer: %p\n", misaligned);// 设置对齐检查位__asm__ volatile("pushf \n\t orl $0x40000, (%rsp) \n\t popf");// 尝试通过misaligned指针写入数据*misaligned = 0x12345678;// 如果没有触发SIGBUS,这行代码会执行printf("No SIGBUS, data written: %d\n", temp_value);// 恢复原始的EFLAGS值__asm__ volatile("push %0 \n\t popf" : : "r"(original_eflags));return temp_value;
}
这段 C 语言代码的主要目的是演示在 x86 架构下处理未对齐内存访问时触发的SIGBUS信号。具体步骤如下:
- 包含必要的头文件,并定义全局变量用于存储原始的 EFLAGS 寄存器值和一个临时变量。
- 编写信号处理函数,当捕获到
SIGBUS信号时,输出提示信息,恢复原始 EFLAGS 值,然后终止程序。 - 在
main函数中,首先安装SIGBUS信号处理器,接着准备一个未对齐的内存地址。 - 保存并打印原始的 EFLAGS 值和对齐检查位的状态,然后设置对齐检查位。
- 尝试通过未对齐的指针写入数据,若触发
SIGBUS信号则进入信号处理函数;若未触发,则输出提示信息。 - 最后恢复原始的 EFLAGS 值,并返回临时变量。
编译执行,可以出现SIGBUS信号,解决也很简单,只有将地址对齐即可:
ubuntu->tools:$ gcc sigbus_alignment.c -O0 -o sigbus_alignment.out
ubuntu->tools:$ ./sigbus_alignment.out
Original EFLAGS: 0x206
Alignment Check Bit: Disabled
Misaligned pointer: 0x7ffc32e491f9
Caught SIGBUS: Alignment Fault!
2.2 映射内存大小改变触发SIGBUS信号
测试代码如下:
/** SPDX-License-Identifier: BSD-3-Clause** Copyright (c) 2025 Once Day <once_day@qq.com>, All rights reserved.** @FilePath: /tools/sigbus_mmap.c* @Author: Once Day <once_day@qq.com>.* @Date: 2025-03-17 22:16* @info: Encoder=utf-8,Tabsize=4,Eol=\n.** @Description:* 测试SIGBUS信号**/#define _GNU_SOURCE
#define __USE_GNU#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>static uint64_t mapped_size = 8192;
static uint64_t mapped_size_latest = 4096;
static char *mapped_mem;
static int mapped_fd;// 使用signal longjmp跳转到sigbus_handler
static sigjmp_buf jmpbuf;void sigbus_handler(int sig)
{printf("Caught SIGBUS: Invalid memory access!\n");// 首先取消原有内存映射munmap(mapped_mem, mapped_size);// 重新映射内存mapped_mem =mmap(mapped_mem, mapped_size_latest, PROT_READ | PROT_WRITE, MAP_SHARED, mapped_fd, 0);if (mapped_mem == MAP_FAILED) {perror("mmap");exit(1);}printf("Remapped address: %p\n", mapped_mem);// 继续执行siglongjmp(jmpbuf, 1);
}int main()
{// 安装SIGBUS信号处理器signal(SIGBUS, sigbus_handler);// 创建一个共享内存文件映射mapped_fd = shm_open("test-sigbus", O_CREAT | O_RDWR, 0666);if (mapped_fd == -1) {perror("shm_open");exit(1);}// 删除共享内存文件(确保下次重新映射)shm_unlink("test-sigbus");// 设置文件大小ftruncate(mapped_fd, mapped_size);// 映射共享内存mapped_mem = mmap(NULL, mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, mapped_fd, 0);printf("Mapped address: %p\n", mapped_mem);// 写入数据for (int i = 0; i < mapped_size; i++) {mapped_mem[i] = 'A' + i % 26;}printf("Data written\n");// 重新设置文件大小printf("Truncated file size\n");ftruncate(mapped_fd, mapped_size_latest);// 尝试访问超出映射内存的地址printf("Accessing out-of-bound memory...\n");// 设置长跳转点if (sigsetjmp(jmpbuf, 1) == 0) {// 尝试访问超出映射内存的地址mapped_mem[mapped_size_latest] = 0;} else {// 如果发生SIGBUS,长跳转到这里printf("Check mapped file length has been changed\n");printf("Read data under new size: %c\n", mapped_mem[mapped_size_latest - 1]);}// 如果没有触发SIGBUS,这行代码会执行printf("End of program\n");return 0;
}
这段 C 语言代码的主要目的是测试SIGBUS信号,模拟内存映射文件大小改变后,访问超出新文件大小的内存区域触发SIGBUS信号的情况,并对该信号进行处理。具体步骤如下:
- 头文件和全局变量:包含必要的系统头文件,定义全局变量用于记录映射内存的大小、文件描述符和映射内存地址,同时使用
sigjmp_buf用于长跳转。 - 信号处理函数:定义
sigbus_handler函数,当捕获到SIGBUS信号时,先取消原有内存映射,再重新映射内存,若映射失败则输出错误信息并退出程序。最后使用siglongjmp跳转到之前设置的跳转点继续执行。 main函数,安装SIGBUS信号处理器,创建一个共享内存文件映射,删除该文件以确保下次重新映射,设置文件大小并进行内存映射。向映射内存写入数据。重新设置文件大小,尝试访问超出新文件大小的内存地址。使用sigsetjmp设置长跳转点,若触发SIGBUS信号,跳转到相应代码块,输出检查信息并读取新大小下的最后一个字符。若未触发SIGBUS信号,输出程序结束信息并返回。
编译执行,可以出现SIGBUS信号,解决方法可以是重新映射共享内存,并且同步修改访问内存的变量值。
ubuntu->tools:$ gcc sigbus_mmap.c -O0 -g -o sigbus_mmap.out
ubuntu->tools:$ ./sigbus_mmap.out
Mapped address: 0x7f7738469000
Data written
Truncated file size
Accessing out-of-bound memory...
Caught SIGBUS: Invalid memory access!
Remapped address: 0x7f7738469000
Check mapped file length has been changed
Read data under new size: N
End of program
3. 总结
一般而已,对齐问题主要影响性能,所以在面对热点代码时,需要保证核心数据结构对齐,特别是对于原子操作,需要尽可能在一个cache line内。
对于文件映射内存后,文件大小发生改变,这种情况下需要重新映射共享内存,直接重启应用是非常不错的选项,如果无法重启应用,可尝试在信号处理函数里面重新映射共享内存,并且修改相关的变量信息。
对于存在异常捕获的编程语言,如C++和Python,这一步很好操作,但是对于C语言,需要借助setjmp来完成退栈操作。
相关文章:
Linux错误(2)程序触发SIGBUS信号分析
Linux错误(2)之SIGBUS错误分析 Author: Once Day Date: 2025年3月12日 一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦… 漫漫长路,有人对你微笑过嘛… 全系列文章可参考专栏: Linux实践记录_Once_day的博…...
【Halcon】灰度不均解决方案
目录 1、平场校正 2、形态学背景估计 3、频域滤波抑制低频光照不均 4、动态局部自适应 1、平场校正 原理:通过白场(White Image)和黑场(Black Image)图像,手动计算校正系数 * 读取图像 read_image(ImageRaw, raw_image) // 原始图像 read_image(ImageWhite, …...
滑动窗口算法详解:从入门到精通
目录 引言 1. 滑动窗口算法简介 2. 滑动窗口的基本思想 3. 滑动窗口的应用场景 3.1 最大子数组和 3.2 最小覆盖子串 3.3 最长无重复字符子串 4. 滑动窗口的实现步骤 5. 滑动窗口的代码示例 6. 滑动窗口的优化技巧 6.1 使用哈希表记录字符频率 6.2 使用双指针维护窗口…...
JAVA数据库技术(一)
JDBC 简介 JDBC(Java Database Connectivity)是Java平台提供的一套用于执行SQL语句的Java API。它允许Java程序连接到数据库,并通过发送SQL语句来查询、更新和管理数据库中的数据。JDBC为不同的数据库提供了一种统一的访问方式,使…...
LightGBM + TA-Lib A股实战进阶:Optuna调优与Plotly可视化详解
LightGBM TA-Lib A 股实战进阶:Optuna 调优与 Plotly 可视化详解 本文系统讲解了 LightGBM 在 A 股市场的应用,涵盖模型构建、Optuna 参数调优及 Plotly 可视化。通过实战案例,帮助读者全面掌握相关技术,提升在金融数据分析与预测…...
第二:go 链接mysql 数据库
mac mysql 安装 的步骤 mysql 安装 配制: https://juejin.cn/post/7454870544929472550 mac brew 如何安装mysql数据库 要在Mac上使用Homebrew安装MySQL数据库,请按照以下步骤操作:步骤 1: 安装Homebrew 如果你还没有安装Homebrew&a…...
QListView、QListWidget、QTableView和QTableWidget
一、概念 在Qt框架中,QListView、QListWidget、QTableView和QTableWidget都是用于显示列表或表格数据的控件。 QListView是一个基于模型-视图架构的控件,用于展示列表形式的数据。它本身并不存储数据,而是依赖于一个QAbstractListModel或其子…...
[贪心算法]-最大数(lambda 表达式的补充)
1.解析 我们一般使用的排序比较大小都是 a>b 那么a在b的前面 ab 无所谓 a<b a在b的后面 本题的排序则是 ab>ba 那么a在b的前面 abba 无所谓 ab<ba a在b的后面 2.代码 class Solution { public:string largestNumber(vector<int>& nums) {//1.先把所有…...
C语言 —— 此去经年梦浪荡魂音 - 深入理解指针(卷二)
目录 1. 数组名与地址 2. 指针访问数组 3.一维数组传参本质 4.二级指针 5. 指针数组 6. 指针数组模拟二维数组 1. 数组名与地址 我们先看下面这个代码: int arr[10] { 1,2,3,4,5,6,7,8,9,10 };int* p &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数…...
python实现简单的图片去水印工具
python实现简单的图片去水印工具 使用说明: 点击"打开图片"选择需要处理的图片 在图片上拖拽鼠标选择水印区域(红色矩形框) 点击"去除水印"执行处理 点击"保存结果"保存处理后的图片 运行效果 先简要说明…...
使用dify+deepseek部署本地知识库
使用difydeepseek部署本地知识库 一、概述二、安装windows docker desktop1、确认系统的Hyper-v功能正常启用2、docker官网下载安装windows客户端3、安装完成后的界面如下所示 三、下载安装ollama四、部署本地deepseek五、本地下载部署dify5.1 下载dify的安装包5.2 将dify解压到…...
(C语言)指针与指针数组的使用教学(C语言基础教学)(指针教学)
指针是什么?指针怎么用?指针数组又是什么??? 想必大家刚学C语言的时候对指针可谓是十分头疼了,听也听不懂,用也不会用 下面我来用我的理解来教你指针怎么用,还你一个脑子 1.指针的…...
【算法day13】最长公共前缀
最长公共前缀 https://leetcode.cn/problems/longest-common-prefix/submissions/612055945/ 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 “”。 class Solution { public:string longestCommonPrefix(vector<string&g…...
Effective C++ 剖析(条款1~9)
目录 条款01 视C为一个语言联邦(C由几部分组成) 条款02 尽量以 const,enum,inline 替换 #define 条款03 尽量使用 const 条款04 确定对象再使用前已经被初始化 条款05 了解c默默编写并调用那些函数 条款06 若不想使用编译器自动生成的函数就该明确拒绝 条款07 为多态基类…...
【Maven-plugin】有多少官方插件?
之前疏理了容器底层原理,现在回归主题,在阅读 next-public时发现 parent 将从多基础插件集成到 parent 仓库中单独维护,数量众多,故在此将所有插件分类整理。以达观其全貌,心中有数。 以下是 Apache Maven 官方维护的核心插件列表…...
Java高频面试之集合-13
hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶 面试官:为什么 hash 函数能降哈希碰撞? 哈希函数通过以下核心机制有效降低碰撞概率,确保不同输入尽可能映…...
RGV调度算法(三)--遗传算法
1、基于时间窗 https://wenku.baidu.com/view/470e9fd8b4360b4c2e3f5727a5e9856a57122693.html?_wkts_1741880736197&bdQuery%E7%8E%AF%E7%A9%BF%E8%B0%83%E5%BA%A6%E7%AE%97%E6%B3%95 2.2019年MathorCup高校数学建模挑战赛B题 2019-mathorcupB题-环形穿梭机调度模型&a…...
【数学建模】一致矩阵的应用及其在层次分析法(AHP)中的性质
一致矩阵在层次分析法(AHP)中的应用与性质 在层次分析法(AHP)中,一致矩阵是判断矩阵的一种理想状态,它反映了决策者判断的完全合理性和一致性,也就是为了避免决策者认为“A比B重要,B比C重要,但是C又比A重要”的矛盾。…...
YOLOv8轻量化改进——Coordinate Attention注意力机制
现在针对YOLOv8的架构改进越来越多,今天尝试引入了Coordinate Attention注意力机制以改进对小目标物体的检测效率。 yolov8的下载和安装参考我这篇博客: 基于SeaShips数据集的yolov8训练教程_seaships处理成yolov8-CSDN博客 首先我们可以去官网找到CA注…...
php开发转go的学习计划及课程资料信息
以下是为该课程体系整理的配套教材和教程资源清单,包含书籍、视频、官方文档和实战项目资源,帮助你系统化学习: Go语言学习教材推荐(PHP开发者适配版) 一、核心教材(按学习阶段分类) 1. 基础语法阶段(阶段一) 资源类型名称推荐理由链接/获取方式官方教程Go语言之旅交…...
解释 TypeScript 中的枚举(enum),如何使用枚举定义一组常量?
枚举(Enum) 是 TypeScript 中用于定义一组具名常量的核心类型,通过语义化的命名提升代码可读性,同时利用类型检查减少低级错误。 以下从定义方式、使用建议、注意事项三方面深入解析。 一、枚举的定义方式 1. 数字枚举 特性&…...
基于SpringBoot+Vue的驾校预约管理系统+LW示例参考
1.项目介绍 系统角色:管理员、普通用户、教练功能模块:用户管理、管理员管理、教练管理、教练预约管理、车辆管理、车辆预约管理、论坛管理、基础数据管理等技术选型:SpringBoot,Vue等测试环境:idea2024,j…...
ONNX:统一深度学习工作流的关键枢纽
引言 在深度学习领域,模型创建与部署的割裂曾是核心挑战。不同框架训练的模型难以在多样环境部署,而 ONNX(Open Neural Network Exchange)作为开放式神经网络交换格式,搭建起从模型创建到部署的统一桥梁,完…...
蓝桥杯————23年省赛 ——————平方差
3.平方差 - 蓝桥云课 一开始看题我还没有意识到问题的严重性 我丢,我想 的是用两层循环来做,后来我试了一下最坏情况,也就是l1 r 1000000000 结果运行半天没运行出来,我就知道坏了,孩子们,要出事&#…...
一、串行通信基础知识
一、串行通信基础知识 1.处理器与外部设备通信有两种方式 并行通信:数据的各个位用多条数据线同时传输。(传输速度快,但占用引脚资源多。) 串行通信:将数据分成一位一位的形式在一条数据线上逐个传输。(线路…...
自带多个接口,完全免费使用!
做自媒体的小伙伴们,是不是经常为语音转文字的事儿头疼? 今天给大家推荐一款超实用的语音转文字软件——AsrTools,它绝对是你的得力助手! AsrTools 免费的语音转文字软件 这款软件特别贴心,完全免费,而且操…...
大数据学习(70)-大数据调度工具对比
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
Qt QML解决SVG图片显示模糊的问题
前言 在QML中直接使用SVG图片,使用Image控件加载资源,显示出来图片是模糊的,很影响使用体验。本文介绍重新绘制SVG图片,然后注册到QML中使用。 效果图: 左边是直接使用Image加载资源显示的效果 右边是重绘后的效果 …...
【Linux我做主】基础命令完全指南上篇
Linux基础命令完全指南【上篇】 Linux基础命令完全指南github地址前言命令行操作的引入Linux文件系统树形结构的根文件系统绝对路径和相对路径适用场景Linux目录下的隐藏文件 基本指令目录和文件相关1. ls2. cd和pwdcdpwd 3. touch4. mkdir5. cp6. mv移动目录时覆盖写入的两种特…...
Designing Dashboards with SAP Analytics Cloud
Designing Dashboards with SAP Analytics Cloud...
