#Linux动态大小裁剪以及包大小变大排查思路
1 动态库裁剪
库分为动态库和静态库,动态库是在程序运行时才加载,静态库是在编译时就加载到程序中。动态库的大小通常比静态库小,因为动态库只包含了程序需要的函数和数据,而静态库则包含了所有的函数和数据。静态库可以理解为引入源码编译,链接器在链接过程中会自动分析需要可不需要的代码进行删除裁剪。因此静态库不存在包大小问题(除了特定平台生成静态库过大导致无法生成库文件的问题)。
动态库裁剪的思路很简单:
- 通过工具或者编译选项删除不必要的数据和代码;
- 只导出需要的函数和数据;
- 关闭不必要的语言特性,如C++的异常处理等;
- 优化代码,比如能用
constexpr
实现的尽量用constexpr
实现;
1.1 代码层面
首先代码层面,需要尽可能确保不同模块之间的耦合度低,避免出现循环依赖的情况。其次,需要尽可能减少代码的重复,避免出现冗余代码的情况。最后,需要尽可能减少代码的复杂度,避免出现复杂的算法和数据结构的情况。对于一些能够用constexpr
实现的功能,尽量用constexpr
实现,这样可以减少动态库的大小。
C++中容易导致C++膨胀的代码:
- 模板函数和模板类。模板函数和模板类在实例化时都会有一个对应版本的实例,如果任何函数都通过编译器的默认推导来实例化很容易导致膨胀。因此模板函数和模板类应该尽量避免使用默认推导,尽可能显示推导能减少实例化版本。因此可以使用类型擦除和显示实例化来解决模板膨胀的问题。
- 内联函数。内联函数在编译时会被展开,因此内联函数的代码会被复制到调用处,这样会导致代码膨胀。因此内联函数应该尽量避免使用,除非函数的代码量很小。但是这一条对于现代C++ inline的含义已经发生了变化,inline优化基本完全由C++编译器自动优化。
- 宏。宏在编译时会被替换,因此宏的代码会被复制到调用处,这样会导致代码膨胀。因此宏应该尽量避免使用,除非宏的代码量很小。
- 异常处理。异常处理会导致代码膨胀,因为异常处理需要在运行时进行,因此异常处理会导致代码膨胀。因此异常处理应该尽量避免使用,除非异常处理的代码量很小。异常处理通常需要存储异常栈回溯相关的信息,因此容易导致代码膨胀。
- RTTI。RTTI 允许在运行时获取对象的类型信息。 RTTI 需要在代码中插入额外的类型信息,这会增加二进制文件的大小。
- 虚函数表。虚函数表是一个指针数组,它包含了虚函数的地址。虚函数表需要在运行时进行查找,这会增加二进制文件的大小。但是一般情况下,虚函数表的大小是固定的,因此虚函数表的大小并不是二进制膨胀的主要原因。
1.2 编译选项
通过编译选项可以控制编译器的行为,从而控制编译过程中的优化和裁剪。编译选项通常是通过编译器的命令行参数来设置的。常用的降低二进制大小的编译选项有:
- 优化等级,在编译动态库时,使用 -O2 或 -O3 优化级别。 这些优化级别可以使编译器生成更紧凑的代码,从而减小动态库的大小。或者使用
-Os
之类平衡性能和大小的选项。 - 代码裁剪。
-function-sections
:将每个函数放入单独的代码段。-gc-sections
:在链接时删除未使用的代码段。-Wl,--gc-sections
:在链接时删除未使用的代码段。
- LTO。使用链接时优化(Link-Time Optimization, LTO)可以进一步减小动态库的大小。 LTO 允许编译器在链接时进行全局优化,从而消除冗余代码和数据。
-flto
:启用 LTO 优化。-fwhole-program
:启用 LTO 优化。
1.3 导出符号
导出符号是指动态库中可以被其他模块(例如可执行文件或其他动态库)访问的函数和变量。 换句话说,它们是库的公共接口。默认情况下,在 Linux 系统中,使用 GCC 或 Clang 编译动态库时,所有非 static 的函数和全局变量都会被导出。 这通常会导致导出过多的符号,增加库的大小。导出符号越多,库的大小越大。 通过只导出必要的符号,可以显著减小库的大小。
控制导出符号不同编译器提供的方式不同,但是一般来说,有以下几种方式:
- 通过导出文件指定导出的符号列表;
- 代码中通过标记来标记需要导出的函数。
#ifndef MY_LIBRARY_EXPORT_H
#define MY_LIBRARY_EXPORT_H#ifdef _WIN32#ifdef MY_LIBRARY_BUILD#define MY_EXPORT __declspec(dllexport)#else#define MY_EXPORT __declspec(dllimport)#endif
#elif defined(__GNUC__)#define MY_EXPORT __attribute__((visibility("default")))
#else#define MY_EXPORT
#endif#endif // MY_LIBRARY_EXPORT_H
1.4 strip
通常情况下,二进制产物会包含一些调试信息,比如符号表、调试符号等。这些信息对于调试和分析二进制文件非常有用,但是它们通常不会被用于发布版本。因此,在发布版本中,通常会使用strip
工具来去除这些调试信息,从而减小二进制文件的大小。
- 不可逆操作:
strip
命令会直接修改文件,并且无法恢复。 因此,在运行strip
命令之前,请务必备份文件。 - 影响调试: 移除符号表和调试信息会使调试变得更加困难。 如果需要调试程序,请不要运行
strip
命令。 - 发布版本:
strip
命令通常用于发布最终版本的程序,以减小文件大小并提高安全性。 - 调试信息分离: 可以使用
--only-keep-debug
和--add-gnu-debuglink
选项将调试信息分离到单独的文件中。 这样可以在不影响程序运行的情况下进行调试。
2 实验
2.1 测试代码和环境
我们的测试环境是:
Linux DESKTOP-JLHBOB4 4.4.0-19041-Microsoft #4355-Microsoft Thu Apr 12 17:37:00 PST 2024 x86_64 x86_64 x86_64 GNU/Linux
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
测试代码如下,分别是一个头文件和一个源文件编译成so库:
// my_lib.h
#ifndef MY_LARGE_LIBRARY_H
#define MY_LARGE_LIBRARY_H#include <iostream>
#include <vector>// 用于控制导出符号,可以参考之前的通用 EXPORT 宏
#ifdef _WIN32#ifdef MY_LARGE_LIBRARY_BUILD#define MY_LARGE_LIBRARY_API __declspec(dllexport)#else#define MY_LARGE_LIBRARY_API __declspec(dllimport)#endif
#elif defined(__GNUC__)#define MY_LARGE_LIBRARY_API __attribute__((visibility("default")))
#else#define MY_LARGE_LIBRARY_API
#endif// 模板类
template <typename T>
class MY_LARGE_LIBRARY_API MyTemplateClass {
public:MyTemplateClass(T value);T getValue() const;
private:T m_value;
};// 内联函数
inline int MY_LARGE_LIBRARY_API inlineFunction(int x) {return x * x * x; // 复杂的计算,增加内联的代价
}// 虚基类
class MY_LARGE_LIBRARY_API BaseClass {
public:BaseClass(int id);virtual ~BaseClass();virtual int calculate() const;int getId() const;
protected:int m_id;
};// 派生类
class MY_LARGE_LIBRARY_API DerivedClass : public BaseClass {
public:DerivedClass(int id, double factor);~DerivedClass() override;int calculate() const override;
private:double m_factor;
};// 一个导出函数,使用了上述的类和函数
MY_LARGE_LIBRARY_API int processData(const std::vector<int>& data);#endif // MY_LARGE_LIBRARY_H
// my_lib.cpp
#include "Mylib.hpp"
#include <numeric> // std::accumulate// 模板类的实现
template <typename T>
MyTemplateClass<T>::MyTemplateClass(T value) : m_value(value) {}template <typename T>
T MyTemplateClass<T>::getValue() const {return m_value;
}// 显式实例化一些常用的模板类型,减少编译单元间的重复实例化
template class MY_LARGE_LIBRARY_API MyTemplateClass<int>;
template class MY_LARGE_LIBRARY_API MyTemplateClass<double>;// 基类的实现
BaseClass::BaseClass(int id) : m_id(id) {}BaseClass::~BaseClass() {}int BaseClass::calculate() const {return m_id * 2;
}int BaseClass::getId() const {return m_id;
}// 派生类的实现
DerivedClass::DerivedClass(int id, double factor) : BaseClass(id), m_factor(factor) {}DerivedClass::~DerivedClass() {}int DerivedClass::calculate() const {return static_cast<int>(m_id * m_factor * 3);
}// processData 函数的实现
int processData(const std::vector<int>& data) {int sum = std::accumulate(data.begin(), data.end(), 0);int inlinedResult = inlineFunction(sum);MyTemplateClass<int> templateObject(inlinedResult);BaseClass* baseObject = new DerivedClass(sum, 2.5);int finalResult = templateObject.getValue() + baseObject->calculate();delete baseObject;return finalResult;
}
2.1.2 不同操作对二进制大小的影响
默认 | -O1 | -O2 | -O3 | -Os | 符号 | section | lto | whole | rtti | 异常 | debug | strip | 包大小(Byte) |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
√ | 57400 | ||||||||||||
√ | √ | 53752 | |||||||||||
√ | √ | 53560 | |||||||||||
√ | √ | 54784 | |||||||||||
√ | √ | 53464 | |||||||||||
√ | √ | √ | 53480 | ||||||||||
√ | √ | √ | √ | 53936 | |||||||||
√ | √ | √ | √ | √ | 23120 | ||||||||
√ | √ | √ | √ | √ | √ | 10408 | |||||||
√ | √ | √ | √ | √ | √ | √ | 10016 | ||||||
√ | √ | √ | √ | √ | √ | √ | √ | 10016 | |||||
√ | √ | √ | √ | √ | √ | √ | √ | √ | 9640 | ||||
√ | √ | √ | √ | √ | √ | √ | √ | √ | √ | 6008 |
下面是不同配置的详细说明:
- 默认配置:使用默认的编译选项和编译方式,不进行任何裁剪和优化。
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylib.so
- 使用不同优化选项对比,具体
-O0
、-O1
、-O2
、-O3
。 - 隐藏符号:使用
-fvisibility=hidden
选项隐藏所有符号。g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_hidden.so -fvisibility=hidden -Os
- 独立section裁剪:使用
-ffunction-sections
和-fdata-sections
选项将每个函数和数据放入单独的代码段和数据段。g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections.so -ffunction-sections -fdata-sections -Os
lto
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections_lto.so -ffunction-sections -fdata-sections -Os -Wl,--gc-sections -flto
- 更激进的优化:
-fwhole-program
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections_lto_whole.so -ffunction-sections -fdata-sections -Os -Wl,--gc-sections -flto -fwhole-program
- 禁用RTTI:
-fno-rtti
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections_lto_whole_nortti.so -ffunction-sections -fdata-sections -Os -Wl,--gc-sections -flto -fwhole-program -fno-rtti
- 禁用异常
-fno-exceptions
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections_lto_whole_nortti_noex.so -ffunction-sections -fdata-sections -Os -Wl,--gc-sections -flto -fwhole-program -fno-rtti -fno-exceptions
- 分离调试信息:
-gsplit-dwarf
g++ -fPIC -shared Mylib.cpp -g -DMY_LARGE_LIBRARY_BUILD -o mylibos_sections_lto_whole_nortti_noex_debuginfo.so -ffunction-sections -fdata-sections -Os -Wl,--gc-sections -flto -fwhole-program -fno-rtti -fno-exceptions -gsplit-dwarf
- 删除无用的信息:
strip
strip -g -x -s mylib.so
从上面的结果来看我们上面大部分操作都可以减少二进制,而且效果明显,我们的库从最开始的57400Byte减少到了6008Byte。能够看到成效是非常明显的。但是本来预期能够降低包大小的操作没有降低包大小的同时,反而增加了包大小这是为什么。
实际工程中往往限制导出符号比较能够降低包大小,上面的实验没有降低包大小的原因是因为我们的测试代码非常简单函数太少,因此包大小的优化效果不是很明显。以及一些其他参数没有降低包大小的原因也是因为我们的测试代码比较简单。
2.1 包大小排查思路
下面我们就简单排查下。
根据上面的数据我们能够看到有两个选项导致了包大小变大,分别是-O3
和gc-sections
,前者是因为该选项更倾向于优化性能而牺牲存储空间,因此已经有明确的结论不需要我们去排查。但是我们期望gc-sections
等选项带来的是包大小优化,但是事实却不是如此。
首先,对于一个二进制动态库,其有不同的section组成,为了确认包大小变大的原因我们首先要做的是确认是哪个section变大了。因此我们使用objdump -h
工具拆分二进制包来确认哪个部分增大了。下面是拆分得到的结果:
27 .debug_aranges 00000080 0000000000000000 DEBUG
30 .debug_line 000005f1 0000000000000000 DEBUG
31 .debug_str 00003bbe 0000000000000000 DEBUG
33 .debug_ranges 00000180 0000000000000000 DEBUG27 .debug_aranges 00000110 0000000000000000 DEBUG
30 .debug_line 0000055f 0000000000000000 DEBUG
31 .debug_str 00003bae 0000000000000000 DEBUG
33 .debug_ranges 000000f0 0000000000000000 DEBUG
从上面的拆包能够看到增加的主要是调试信息。而这部分调试信息在后续的strip
中已经被删除了,因此影响我们最终产物大小的额外因素已经被排除了。如果希望知道具体增大了什么可以通过相关的提取对应section的信息来确认哪一部分增大了。
上面的排查路径其实不是很典型,因为一般情况下包大小都是因为代码引起的
下面简单描述下如何排查包大小问题:
- 首先,对比的产物一定是相同编译参数下的最终产物,使用两个带调试信息的不同编译参数的包对比没有意义(因此排查的前提是代码相同编译参数不同或者编译参数相同代码更改);
- 准备好后,使用
objdump -h
分析不同section的大小,来确认方向:- 不同section对应不同的数据,一般情况下比较容易出现增大的是data和text段
.text
: 代码段,包含可执行指令。 如果包大小增加主要是 .text section 变大,则需要关注代码优化。.rodata
: 只读数据段,包含字符串常量、只读变量等。 大量的字符串常量或嵌入式资源会增加此 section 的大小。.data
: 已初始化数据段,包含已初始化的全局变量和静态变量。 大的静态数组或全局变量会增加此 section 的大小。
- 明确具体包大小变化比较大的section后,可以尝试对比代码变动来初步确定变大的根本原因,如果无法确定则继续;
- 使用命令
nm -CS <your_binary> | sort -rnk1
对代码段和数据段进行排序,然后对比不同版本之间的差异。 - 找到差异的具体部分之后再使用
objdump -d
反汇编并对比源码来确认最终原因。
emsp; 需要注意的是,有些博客会推荐使用
bloaty
,个人建议如果能够通过该工具排查发现数据异常,推荐直接使用linux native的工具链。(在实际项目中发现bloaty
似乎统计的不是很准确。)
相关文章:
#Linux动态大小裁剪以及包大小变大排查思路
1 动态库裁剪 库分为动态库和静态库,动态库是在程序运行时才加载,静态库是在编译时就加载到程序中。动态库的大小通常比静态库小,因为动态库只包含了程序需要的函数和数据,而静态库则包含了所有的函数和数据。静态库可以理解为引入…...
天梯赛数据结构合集
1.集合操作:PTA | 程序设计类实验辅助教学平台 主要是注意set的取交集操作,AC代码: #include<bits/stdc.h> using namespace std; int n,m,k; set<int> a[60]; int main(){cin>>n;for(int i1;i<n;i){cin>>m;for…...
pdfjs库使用记录1
import React, { useEffect, useState, useRef } from react; import * as pdfjsLib from pdfjs-dist; // 设置 worker 路径 pdfjsLib.GlobalWorkerOptions.workerSrc /pdf.worker.min.js; const PDFViewer ({ url }) > { const [pdf, setPdf] useState(null); const […...
LIMS引领综合质检中心数字化变革,赋能质量强国战略
在质量强国战略的深入推进下,我国综合质检机构迎来了前所未有的发展机遇,同时也面临着诸多严峻挑战。随着检测领域从传统的食品药品监督向环境监测、新材料检测等新兴领域不断拓展,跨领域协同管理的复杂度呈指数级增长。作为提升产品质量的关…...
MySQL+Redis实战教程:从Docker安装部署到自动化备份与数据恢复20250418
MySQLRedis实战教程:从Docker安装部署到自动化备份与数据恢复 一、前言 在企业应用中,对MySQL和Redis运维的要求越来越高: 不能仅是启动就算部署运行稳定、隔离、访问控制、备份恢复、安全可靠,才是 企业级的基本功能 本文将手…...
嵌入式音视频开发指南:从MPP框架到QT实战全解析
嵌入式音视频开发指南:从MPP框架到QT实战全解析 一、音视频技术全景概述 1.1 技术演进里程碑 2003-2010年:标清时代(H.264/AVC + RTMP)2011-2018年:高清时代(H.265/HEVC + WebRTC)2019-至今:智能时代(AV1 + AI编解码 + 低延迟传输)1.2 现代音视频技术栈 #mermaid-s…...
如何使用Python进行自动化的系统管理?
Python已经成为系统管理员最流行的编程语言之一,因为它简单、灵活,并且广泛支持各种系统管理任务。无论您是自动执行重复性任务,管理文件和目录,还是处理用户权限,Python都提供了一组强大的工具来简化您的工作流程。 …...
拆机装机,通电主板亮灯风扇不转无法开机解决办法
电源开机线 重启线 usb耳机模块 灯线 看来电源没问题 参考https://zhidao.baidu.com/question/83939532/answer/2321171868.html 买了个新主板过几天到看看会不会好...
IntelliSense 已完成初始化,但在尝试加载文档时出错
系列文章目录 文章目录 系列文章目录前言一、原因二、使用步骤 前言 IntelliSense 已完成初始化,但在尝试加载文档时出错 File path: E:\QtExercise\DigitalPlatform\DigitalPlatform\main\propertyWin.ui Frame GUID:96fe523d-6182-49f5-8992-3bea5f7e6ff6 Frame …...
SuperMap iClient3D for WebGL 如何加载WMTS服务
在 SuperMap iClient3D for WebGL 中加载WMTS服务时,参数配置很关键!下面我们详细介绍如何正确填写参数,确保影像服务完美加载。 一、数据制作 对于上述视频中的地图制作,此处不做讲述,如有需要可访问:Onl…...
[密码学实战]基于Python的国密算法与通用密码学工具箱
引言 在当今数字化浪潮中,信息安全已成为个人隐私保护与商业机密守护的核心议题。作为一位在密码学领域深耕多年的技术实践者,我深谙密码学工具在构建数字安全防线中的关键作用。正是基于这份认知与责任,我倾力打造了一款全方位、高性能的密…...
[密码学实战]详解gmssl库与第三方工具兼容性问题及解决方案
[密码学实战]详解gmssl库与第三方工具兼容性问题及解决方案 引言 国密算法(SM2/SM3/SM4)在金融、政务等领域广泛应用,但开发者在集成gmssl库实现SM2签名时,常遇到与第三方工具(如OpenSSL、国密网关)验证不…...
LIB-ZC, 一个跨平台(Linux)平台通用C/C++扩展库, stream 流操作
LIB-ZC, 一个跨平台(Linux)平台通用C/C扩展库, stream 流操作 lib-zc 封装了流操作命名空间 zcc基础类 stream(基类), iostream(io流封装) class stream 介绍 连接相关 // 都是虚函数, 为 iostream 等做准备virtual inline bool connect(const char *destination) { return …...
从零开始解剖Spring Boot启动流程:一个Java小白的奇幻冒险之旅
大家好呀!今天我们要一起探索一个神奇的话题——Spring Boot的启动流程。我知道很多小伙伴一听到"启动流程"四个字就开始头疼,别担心!我会用最通俗易懂的方式,带你从main()方法开始,一步步揭开Spring Boot的…...
概率多假设跟踪(PMHT):多目标跟踪中的概率软关联与高效跟踪算法解析
一、PMHT 的起源与核心定位 (一)背景 在多目标跟踪中,传统算法面临以下瓶颈: JPDA:单帧局部最优关联,无法处理跨帧长时间断联,且假设目标数固定(如雷达跟踪中预设目标数范围&…...
4.信号和槽|存在意义|信号和槽的连接方式|信号和槽断开|lambda表达式|信号和槽优缺点(C++)
信号和槽存在意义 所谓的信号槽,终究要解决的问题,就是响应用户的操作 信号槽,其实在GUI开发的各种框架中,是一个比较有特色的存在 其他的GUI开发框架,搞的方式都要更简洁一些~~ 网页开发 (js dom api) 网…...
电脑 BIOS 操作指南(Computer BIOS Operation Guide)
电脑 BIOS 操作指南 电脑的BIOS界面(应为“BIOS”)是一个固件界面,允许用户配置电脑的硬件设置。 进入BIOS后,你可以进行多种设置,具体包括: 1.启动配置 启动顺序:设置从哪个设备启动&#x…...
Scrapeless Scraping Browser: A high-concurrency automation solution for AI
介绍:升级无缝抓取浏览器的并发能力 作为 Scrapeless 的开发者和创始团队,我们对人工智能自动化的未来充满真诚的热情。我们的使命是创建一个真正为 AI 设计的自动化浏览器。在过去的几年中,从 Browserless.io 到众多云服务供应商推出的“浏…...
Java项目—— 拼图小游戏(进阶版)
项目需求 在拼图小游戏基础版的基础上,完成下列要求: 一、实现更换拼图图片功能 1,给美女,动物,运动菜单按钮添加单击事件(动作监听) 2,当我们点击了美女之后,就会从13…...
解析:深度优先搜索、广度优先搜索和回溯搜索
一、深度优先搜索(DFS) 1. 原理 思想:从起始节点出发,顺着一条路径不断深入,直到到达目标或无路可走,然后回溯到最近的分支点,继续探索其他分支。 应用场景:路径查找、连通性检测、…...
探索大语言模型(LLM):循环神经网络的深度解析与实战(RNN、LSTM 与 GRU)
一、循环神经网络(RNN) 1.1 基本原理 循环神经网络之所以得名,是因为它在处理序列数据时,隐藏层的节点之间存在循环连接。这意味着网络能够记住之前时间步的信息,并利用这些信息来处理当前的输入。 想象一下…...
从零开始开发 MCP Server
作者:张星宇 在大型语言模型(LLM)生态快速演进的今天,Model Context Protocol(MCP)作为连接 AI 能力与真实世界的标准化协议,正逐步成为智能体开发的事实标准。该协议通过定义 Resources&#…...
Oracle日志系统之重做日志和归档日志
Oracle日志系统之重做日志和归档日志 重做日志归档日志 本文讨论Oracle日志系统中对数据恢复非常重要的两个日志:重做日志和归档日志。 重做日志 重做日志,英文名Redo Log,顾名思义,是用来数据重做的,主要使用场景是事…...
嵌入式开发--STM32G4系列硬件CRC支持MODBUS和CRC32
需求 在项目中,需要用到MODBUS CRC16校验,也要用到CRC32的校验,出于效率的考虑,准备用硬件CRC。 CRC 16的参数模型有很多种,我这里用的是MODBUS,对于不同的参数模型,会有不同的参数设置和初值&a…...
基于尚硅谷FreeRTOS视频笔记——4—多任务处理
目录 多任务处理 任务调度 任务的调度策略 优先级不同 优先级相同 多任务处理 通俗来讲就是 能够在同一时间 同时 进行多个任务的处理,这就时多任务处理。 但是,单核处理器一次只能处理一个任务,就是说在while中,任务们只能…...
中小型及初创企业如何实现数字化转型?
在当今动态的商业环境中,财务团队开始肩负起推动企业数字化转型的重任,即从传统的财务规划系统稳步迈向基于商业智能平台和以创新技术为驱动的解决方案领域。这些举措有望提高运营和分析效率,同时依托数据驱动的决策机制,帮助企业…...
java输出、输入语句
先创建一个用于测试的java 编写程序 #java.util使java标准库的一个包,这里拉取Scanner类 import java.util.Scanner;public class VariableTest {public static void main(String[] args) {#创建一个 Scanner 对象Scanner scanner new Scanner(System.in);System.…...
Python基础知识语法归纳总结(数据类型-1)
Python基础知识&语法归纳总结(数据类型) 一、Python基本数据类型 尤其注意,Python中的变量不需要特定的去声明,每个变量在使用前都必须对其进行赋值,它没有类型,我们所说的“类型”是变量所指的内存中对…...
Spring数据访问全解析:ORM整合与JDBC高效实践
目录 一、Spring ORM集成深度剖析 🌟 ORM模块架构设计 核心集成特性: 整合MyBatis示例配置: 二、Spring JDBC高效实践指南 🌟 传统JDBC vs Spring JDBC对比 🌟 JdbcTemplate核心操作示例 批量操作优化…...
哪种电脑更稳定?Mac?Windows?还是云电脑? 实测解密
随着科技的发展进步,电脑已成为当下各类群体的必备产品之一,它的妙用有很多,无论是学生党、打工人还是已经退休的人群或都离不开它的存在。然而,电脑虽好却也差异很大、不同品牌、不同系统、不同配置、不同价位的统统都会有区别。…...
【AI模型学习】关于写论文——论文的审美
文章目录 一、“补丁法”(Patching)1.1 介绍1.2 方法论1.3 实例 二、判断工作的价值2.1 介绍2.2 详细思路2.3 科研性vs工程性 三、novelty以及误区3.1 介绍3.2 举例 看了李沐老师的读论文系列后,总结三个老师提到的有关课题研究和论文写作的三…...
【面经】杭州产链数字科技一面
1.介绍一下自己 面试官您好!我叫***,目前是就读于****计算机科学与技术专业的一名学生。我平时在学校也自学了编程相关的知识,比如Java基础、Springboot、SpringCloud,关系型数据库Mysql,非关系型数据库Redisÿ…...
微信小程序调用yolo目标检测模型
目录 后端 前端微信小程序 完整代码 后端 利用Flask,调用目标检测模型,后端代码如下。 # flask_yolo.py from flask import Flask, request, jsonify from ultralytics import YOLO from PIL import Imageapp Flask(__name__) model_path best.p…...
vmware17 虚拟机 ubuntu22.04 桥接模式,虚拟机无法接收组播消息
问题描述: 在一个项目中,宿主机win10中,使用的vmware17pro 虚拟机安装的ubuntu22.04,按照网上的教程使用Qt绑定组播消息,在另外一个Ubuntu工控机上发送用wiresahrk抓包的组播消息 sudo tcpreplay -i enp1s0 --loop0 y…...
Kaggle-Bag of Words Meets Bags of Popcorn-(二分类+NLP+Bert模型)
Bag of Words Meets Bags of Popcorn 题意: 有很多条电影评论记录,问你每一条记录是积极性的评论还是消极性的评论。 数据处理: 1.首先这是文件是zip形式,要先解压,注意sep ‘\t’。 2.加载预训练的 BERT 分词器 …...
数字信号处理技术架构与功能演进
数字信号处理(DSP)是通过数字运算实现信号分析、变换、滤波及调制解调的技术领域,其发展过程与技术应用如下: 一、定义与核心功能 技术定义:通过算法将模拟信号转换为数字形式进行处理,具有高精度、可编程…...
IaaS架构剖析、场景实践
一、什么是 IaaS 1.1 定义 Infrastructure as a Service(IaaS,基础设施即服务)是一种按需、弹性提供计算、存储、网络和安全等底层 IT 资源的云服务模式。用户通过 API、CLI 或 Web 控制台即可在几分钟内创建、扩容或释放资源,而…...
国产之光DeepSeek架构理解与应用分析02
本专栏 国产之光DeepSeek架构理解与应用分析-CSDN博客 国产之光DeepSeek架构理解与应用分析02-CSDN博客 前置的一些内容理解 GPU TPU NPU的区别? 设计目的 GPU:最初是为了加速图形渲染而设计的,用于处理图像和视频数据,以提供高…...
EDID结构
EDID DDC通讯中传输显示设备数据 VGA , DVI 的EDID由128字节组成,hdmi的EDID增加扩展块128字节。扩展快的内容主要是和音频属性相关的,DVI和vga没有音频,hdmi自带音频,扩展快数据规范按照cea-861x标准。 Edid为了让pc或其他的图像…...
4.黑马学习笔记-SpringMVC(P43-P47)
1.SpringMVC简介 SpringMVC技术(更少的代码,简便)与servlet技术功能相同,属于web层开发技术。 SpringMVC是一种基于java实现MVC模型的轻量级web框架。 轻量级指的是(内存占用比较低,运行效率高)…...
CSS 文件格式
A QFrame#andrFrm[status"android_en"] A:表示父类或顶层窗口的类型。如果 A 是一个自定义的类名,确保该类已经正确注册到 Qt 系统中。QFrame:表示具体的控件类型。#andrFrm:表示控件的对象名称(通过 setOb…...
java输出HelloWorld
创建一个java格式文件,这里命令为HelloWorld 这里我选择用notepad编译,也可以直接用记事本 #public 访问修饰词,表示这个类可以被其他任何类访问 #class 定义类的关键字 #HelloWorld 类名,遵循驼峰命名法(首字母大写…...
【SAP ME 44】在 HANA DB中报废SFC时的SHOP_ORDER表记录锁定
症状 SELECT…FROM SHOP_ORDER FOR UPDATE 在 SFC 报废期间持有锁,当同时调用数量较大时,可能会导致 HANA 数据库出现大量锁积压。这有时会导致因等待 HANA 数据库释放“选择更新”锁而导致报废 SFC 花费数分钟。 HANA 数据库日志中的示例: # begin PreparedStatement_ex…...
《软件设计师》复习笔记(12.1)——范围管理、进度管理
目录 一、范围管理 1. 核心概念 2. 范围管理过程 WBS(工作分解结构)示例 真题示例: 二、进度管理 1. 核心过程 2. 关键工具与技术 真题示例: 一、范围管理 1. 核心概念 项目范围:为交付产品必须完成的工作…...
Git-使用教程(新手向)
一、基本概念: 1.Git,Github的关系: Git --- 本地用于管理代码的工具,可类比为游戏存档。(存档,仓库,项目在Git中是一个东西) Github --- 远程仓库平台,可类比为云端。…...
密码学中的盐值是什么?
目录 1. 盐值的基本概念 2. 盐值的作用 (1) 防止彩虹表攻击 (2) 防止相同的密码生成相同的哈希值 (3) 增加暴力破解的难度 3. 如何使用盐值? (1) 生成盐值 (2) 将盐值附加到密码 (3) 存储盐值和哈希值 (4) 验证密码 4. 盐值如何增加暴力破解的难度 在线暴…...
[工具]Java xml 转 Json
[工具]Java xml 转 Json 依赖 <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.37</version> </dependen…...
安全光幕的CE认证
在工业自动化飞速发展的当下,安全光幕作为保障操作人员安全的关键设备,其重要性不言而喻。对于想要进军欧盟市场的安全光幕制造商来说,CE 认证是必须跨越的一道关卡。今天,我们就来深入探讨安全光幕的 CE 认证流程。 什么是安全…...
DNS解析失败怎么解决?
在互联网时代,畅快地浏览网页、使用各类网络服务已成为生活常态。然而,当屏幕突然弹出 “DNS解析失败”的提示,原本顺畅的网络连接戛然而止,让人倍感困扰。DNS即域名系统,它如同互联网的 “电话簿”,负责将…...
亚马逊商品详情API数据接口概述,Amazon API
亚马逊商品详情API数据接口概述 亚马逊商品详情API(如Amazon Product Advertising API或Selling Partner API (SP-API))是亚马逊为开发者提供的官方接口,允许通过编程方式获取商品的详细信息,包括商品标题、价格、描述、图片、用…...