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

链接库文件体积优化工具篇:bloaty

笔者之前参与过一个嵌入式智能手表项目,曾经碰到过这样一个问题:手表的flash大小只有2M,这意味着只能在上面烧录2M大小的代码。随着开发不断进行,代码越写越多,编译出来的bin也越来越大。最后bin大小超过了2M, 就没法烧写了,很尴尬。最后只能想办法精简代码,当然这是在不影响功能的前提下精简代码。那如何精简代码呢?我们自然会想到先看看哪里的代码最多,比如使用的各个so的大小,so里边哪个源文件最大,源文件里边哪一个函数最耗空间等等,先做一个统计分析,然后再看一下怎么优化。那这个统计如何进行呢?这个就需要用到一些工具。

本文介绍的工具:bloaty就用来干这个活的,这是谷歌公司开源的一个项目,在GitHub上有源码,主要是用来查看可执行文件,链接库内存分布的。Bloaty对二进制文件进行深入分析,使用自定义的ELF、DWARF和Mach-O解析器,旨在将二进制文件的每个字节准确地定位到是属于哪个符号或编译单元。它甚至会反汇编二进制文件,寻找对匿名数据的引用。
下面是一个例子,用bloaty工具来分析bloaty二进制文件,看一下各个编译单元(源文件)所占的内存大小和占总大小的百分比:

./bloaty bloaty -d compileunitsFILE SIZE        VM SIZE    --------------  -------------- 34.8%  10.2Mi  43.4%  2.91Mi    [163 Others]17.2%  5.08Mi   4.3%   295Ki    third_party/protobuf/src/google/protobuf/descriptor.cc7.3%  2.14Mi   2.6%   179Ki    third_party/protobuf/src/google/protobuf/descriptor.pb.cc4.6%  1.36Mi   1.1%  78.4Ki    third_party/protobuf/src/google/protobuf/text_format.cc3.7%  1.10Mi   4.5%   311Ki    third_party/capstone/arch/ARM/ARMDisassembler.c1.3%   399Ki  15.9%  1.07Mi    third_party/capstone/arch/M68K/M68KDisassembler.c3.2%   980Ki   1.1%  75.3Ki    third_party/protobuf/src/google/protobuf/generated_message_reflection.cc3.2%   965Ki   0.6%  40.7Ki    third_party/protobuf/src/google/protobuf/descriptor_database.cc2.8%   854Ki  12.0%   819Ki    third_party/capstone/arch/X86/X86Mapping.c2.8%   846Ki   1.0%  66.4Ki    third_party/protobuf/src/google/protobuf/extension_set.cc2.7%   800Ki   0.6%  41.2Ki    third_party/protobuf/src/google/protobuf/generated_message_util.cc2.3%   709Ki   0.7%  50.7Ki    third_party/protobuf/src/google/protobuf/wire_format.cc2.1%   637Ki   1.7%   117Ki    third_party/demumble/third_party/libcxxabi/cxa_demangle.cpp1.8%   549Ki   1.7%   114Ki    src/bloaty.cc1.7%   503Ki   0.7%  48.1Ki    third_party/protobuf/src/google/protobuf/repeated_field.cc1.6%   469Ki   6.2%   427Ki    third_party/capstone/arch/X86/X86DisassemblerDecoder.c1.4%   434Ki   0.2%  15.9Ki    third_party/protobuf/src/google/protobuf/message.cc1.4%   422Ki   0.3%  23.4Ki    third_party/re2/re2/dfa.cc1.3%   407Ki   0.4%  24.9Ki    third_party/re2/re2/regexp.cc1.3%   407Ki   0.4%  29.9Ki    third_party/protobuf/src/google/protobuf/map_field.cc1.3%   397Ki   0.4%  24.8Ki    third_party/re2/re2/re2.cc100.0%  29.5Mi 100.0%  6.69Mi    TOTAL

Bloaty支持许多功能:

  1. 文件格式:ELF、Mach-O、PE/COFF(实验)、WebAssembly(实验)
  2. 数据来源:compilenit(如上所示)、符号、节、段等。
  3. 分层解析:将多个数据源合并为一个报告
  4. size diffs:查看二进制文件的增长位置,非常适合CI测试
  5. 单独的调试文件:剥离测试中的二进制文件,同时使调试数据可用于分析
  6. 灵活的解映射:解映射C++符号,可选择丢弃函数/模板参数
  7. 自定义数据源:regex重写内置数据源,用于自定义munging/bucketing
  8. 正则表达式过滤:过滤掉二进制文件中与给定正则表达式匹配或不匹配的部分

使用说明

$ ./bloaty bloatyFILE SIZE        VM SIZE    --------------  -------------- 30.0%  8.85Mi   0.0%       0    .debug_info24.7%  7.29Mi   0.0%       0    .debug_loc12.8%  3.79Mi   0.0%       0    .debug_str9.7%  2.86Mi  42.8%  2.86Mi    .rodata6.9%  2.03Mi  30.3%  2.03Mi    .text6.3%  1.85Mi   0.0%       0    .debug_line4.0%  1.19Mi   0.0%       0    .debug_ranges0.0%       0  15.0%  1.01Mi    .bss1.6%   473Ki   0.0%       0    .strtab1.4%   435Ki   6.3%   435Ki    .data0.8%   254Ki   3.7%   254Ki    .eh_frame0.8%   231Ki   0.0%       0    .symtab0.5%   142Ki   0.0%       0    .debug_abbrev0.2%  56.8Ki   0.8%  56.8Ki    .gcc_except_table0.1%  41.4Ki   0.6%  41.4Ki    .eh_frame_hdr0.0%  11.4Ki   0.1%  9.45Ki    [26 Others]0.0%  7.20Ki   0.1%  7.14Ki    .dynstr0.0%  6.09Ki   0.1%  6.02Ki    .dynsym0.0%  4.89Ki   0.1%  4.83Ki    .rela.plt0.0%  4.59Ki   0.0%       0    [Unmapped]0.0%  3.30Ki   0.0%  3.23Ki    .plt100.0%  29.5Mi 100.0%  6.69Mi    TOTAL

“VM SIZE”列告诉二进制文件加载到内存时将占用多少空间。“文件大小”列告诉二进制文件在磁盘上占用的空间。这两者可能彼此非常不同:

  • 有些数据存在于文件中,但没有加载到内存中,例如调试信息。
  • 某些数据已映射到内存中,但文件中不存在。这主要适用于.bss部分(零初始化数据)。

Bloaty中的默认细分是分段的,但支持许多其他对二进制文件进行切片的方式,如符号和分段。如果使用调试信息进行编译,甚至可以按编译单元和内联进行分解!效果见第一个例子。

Size Diffs

可以使用Bloaty来查看二进制文件的大小是如何变化的。
例如,这里有几个不同版本的Bloaty之间的大小差异,显示了当我添加一些功能时它是如何增长的。

$ ./bloaty bloaty -- oldbloatyVM SIZE                     FILE SIZE--------------               --------------[ = ]       0 .debug_loc     +688Ki  +9.9%+19%  +349Ki .text          +349Ki   +19%[ = ]       0 .debug_ranges  +180Ki   +11%[ = ]       0 .debug_info    +120Ki  +0.9%+23% +73.5Ki .rela.dyn     +73.5Ki   +23%+3.5% +57.1Ki .rodata       +57.1Ki  +3.5%+28e3% +53.9Ki .data         +53.9Ki +28e3%[ = ]       0 .debug_line   +40.2Ki  +4.8%+2.3% +5.35Ki .eh_frame     +5.35Ki  +2.3%-6.0%      -5 [Unmapped]    +2.65Ki  +215%+0.5% +1.70Ki .dynstr       +1.70Ki  +0.5%[ = ]       0 .symtab       +1.59Ki  +0.9%[ = ]       0 .debug_abbrev +1.29Ki  +0.5%[ = ]       0 .strtab       +1.26Ki  +0.3%+16%    +992 .bss                0  [ = ]+0.2%    +642 [13 Others]      +849  +0.2%+0.6%    +792 .dynsym          +792  +0.6%+16%    +696 .rela.plt        +696   +16%+16%    +464 .plt             +464   +16%+0.8%    +312 .eh_frame_hdr    +312  +0.8%[ = ]       0 .debug_str    -19.6Ki  -0.4%+11%  +544Ki TOTAL         +1.52Mi  +4.6%

分层解析

Bloaty支持以多种不同的方式分解二进制文件。您可以将多个数据源组合到一个层次配置文件中。例如,我们可以在单个报告中使用分段和分段数据源:

$ ./bloaty -d segments,sections bloatyFILE SIZE        VM SIZE    --------------  -------------- 80.7%  23.8Mi   0.0%       0    [Unmapped]37.2%  8.85Mi   NAN%       0    .debug_info30.6%  7.29Mi   NAN%       0    .debug_loc15.9%  3.79Mi   NAN%       0    .debug_str7.8%  1.85Mi   NAN%       0    .debug_line5.0%  1.19Mi   NAN%       0    .debug_ranges1.9%   473Ki   NAN%       0    .strtab1.0%   231Ki   NAN%       0    .symtab0.6%   142Ki   NAN%       0    .debug_abbrev0.0%  4.59Ki   NAN%       0    [Unmapped]0.0%     392   NAN%       0    .shstrtab0.0%     139   NAN%       0    .debug_macinfo0.0%      68   NAN%       0    .comment10.9%  3.21Mi  47.9%  3.21Mi    LOAD #4 [R]89.3%  2.86Mi  89.3%  2.86Mi    .rodata7.7%   254Ki   7.7%   254Ki    .eh_frame1.7%  56.8Ki   1.7%  56.8Ki    .gcc_except_table1.3%  41.4Ki   1.3%  41.4Ki    .eh_frame_hdr0.0%       1   0.0%       1    [LOAD #4 [R]]6.9%  2.03Mi  30.3%  2.03Mi    LOAD #3 [RX]99.8%  2.03Mi  99.8%  2.03Mi    .text0.2%  3.23Ki   0.2%  3.23Ki    .plt0.0%      28   0.0%      28    [LOAD #3 [RX]]0.0%      23   0.0%      23    .init0.0%       9   0.0%       9    .fini1.5%   439Ki  21.4%  1.44Mi    LOAD #5 [RW]0.0%       0  70.1%  1.01Mi    .bss99.1%   435Ki  29.6%   435Ki    .data0.4%  1.63Ki   0.1%  1.63Ki    .got.plt0.3%  1.46Ki   0.1%  1.46Ki    .data.rel.ro0.1%     560   0.0%     560    .dynamic0.1%     384   0.0%     376    .init_array0.0%      32   0.0%      56    [LOAD #5 [RW]]0.0%      32   0.0%      32    .got0.0%      16   0.0%      16    .tdata0.0%       8   0.0%       8    .fini_array0.0%       0   0.0%       8    .tbss0.1%  23.3Ki   0.3%  23.3Ki    LOAD #2 [R]30.7%  7.14Ki  30.7%  7.14Ki    .dynstr25.9%  6.02Ki  25.9%  6.02Ki    .dynsym20.8%  4.83Ki  20.8%  4.83Ki    .rela.plt7.7%  1.78Ki   7.7%  1.78Ki    .hash5.0%  1.17Ki   5.0%  1.17Ki    .rela.dyn3.1%     741   3.1%     741    [LOAD #2 [R]]2.7%     632   2.7%     632    .gnu.hash2.2%     514   2.2%     514    .gnu.version1.6%     384   1.6%     384    .gnu.version_r0.2%      36   0.2%      36    .note.gnu.build-id0.1%      32   0.1%      32    .note.ABI-tag0.1%      28   0.1%      28    .interp0.0%  2.56Ki   0.0%       0    [ELF Headers]46.3%  1.19Ki   NAN%       0    [19 Others]7.3%     192   NAN%       0    [ELF Headers]2.4%      64   NAN%       0    .comment2.4%      64   NAN%       0    .data2.4%      64   NAN%       0    .data.rel.ro2.4%      64   NAN%       0    .debug_abbrev2.4%      64   NAN%       0    .debug_info2.4%      64   NAN%       0    .debug_line2.4%      64   NAN%       0    .debug_loc2.4%      64   NAN%       0    .debug_macinfo2.4%      64   NAN%       0    .debug_ranges2.4%      64   NAN%       0    .debug_str2.4%      64   NAN%       0    .dynamic2.4%      64   NAN%       0    .dynstr2.4%      64   NAN%       0    .dynsym2.4%      64   NAN%       0    .eh_frame2.4%      64   NAN%       0    .eh_frame_hdr2.4%      64   NAN%       0    .fini2.4%      64   NAN%       0    .fini_array2.4%      64   NAN%       0    .gcc_except_table2.4%      64   NAN%       0    .gnu.hash100.0%  29.5Mi 100.0%  6.69Mi    TOTAL

Bloaty为每个级别显示最多20行;其他值被分组到[other]bin中。使用-n<num>可覆盖此设置。如果传递-n 0,所有数据都将被输出,而不会将任何内容折叠到[Other]中

调试剥离的二进制文件

Bloaty支持从单独的二进制文件中读取调试信息/符号。这使您可以对剥离的二进制文件进行配置,即使是对于像“compilenits”或“symbol”这样需要这些额外信息的数据源也是如此。
Bloaty使用构建ID来验证二进制文件和调试文件是否匹配。否则,结果将是无稽之谈(这种不匹配听起来可能不太可能,但这是一个很容易犯的错误)。
如果您的二进制文件有一个生成ID,那么使用单独的调试文件非常简单,如下所示:

$ cp bloaty bloaty.stripped
$ strip bloaty.stripped
$ ./bloaty -d symbols --debug-file=bloaty bloaty.stripped

数据源

Bloaty有许多内置的数据源。这些都提供了不同的方法来查看二进制文件。您还可以通过将正则表达式应用于内置数据源来创建自己的数据源(请参阅下面的“自定义数据源”)。
虽然Bloaty处理二进制文件、共享对象、对象文件和静态库(.a文件),但有些数据源不处理对象文件。这尤其适用于读取调试信息的数据源。

Segments段

段是运行时加载程序用来确定二进制文件的哪些部分需要加载/映射到内存中的内容。通常只有几个部分:每组mmap()权限需要一个:

$ ./bloaty -d segments bloatyFILE SIZE        VM SIZE    --------------  -------------- 80.7%  23.8Mi   0.0%       0    [Unmapped]10.9%  3.21Mi  47.9%  3.21Mi    LOAD #4 [R]6.9%  2.03Mi  30.3%  2.03Mi    LOAD #3 [RX]1.5%   439Ki  21.4%  1.44Mi    LOAD #5 [RW]0.1%  23.3Ki   0.3%  23.3Ki    LOAD #2 [R]0.0%  2.56Ki   0.0%       0    [ELF Headers]100.0%  29.5Mi 100.0%  6.69Mi    TOTAL

在这里,我们看到一个段被映射[RX](读/执行)和一个段映射[RW](读取/写入)。二进制文件的很大一部分没有加载到内存中,我们将其视为[未映射]。
对象文件和静态库没有段。然而,我们通过将部分按其标志分组来伪造它。这给了我们一个分解,有点像真实的片段。

$ ./bloaty -d segments CMakeFiles/libbloaty.dir/src/bloaty.cc.oFILE SIZE        VM SIZE    --------------  -------------- 87.5%   972Ki   0.0%       0    Section []8.2%  90.9Ki  78.3%  90.9Ki    Section [AX]2.3%  25.2Ki  21.7%  25.2Ki    Section [A]2.0%  22.6Ki   0.0%       0    [ELF Headers]0.1%     844   0.0%       0    [Unmapped]0.0%      24   0.1%      72    Section [AW]100.0%  1.09Mi 100.0%   116Ki    TOTAL

未完待续

相关文章:

链接库文件体积优化工具篇:bloaty

笔者之前参与过一个嵌入式智能手表项目,曾经碰到过这样一个问题:手表的flash大小只有2M,这意味着只能在上面烧录2M大小的代码。随着开发不断进行,代码越写越多,编译出来的bin也越来越大。最后bin大小超过了2M, 就没法烧…...

使用pyqt绘制一个爱心!

使用pyqt绘制一个爱心! 介绍效果代码 介绍 使用pyqt绘制一个爱心! 效果 代码 import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget from PyQt5.QtGui import QPainter, QPen, QBrush, QColor from PyQt5.QtCore import Qt, Q…...

关于 Transformer 的11个常见面试题

Transformer 是如何工作的? Transformer 是一种深度学习算法,特别适用于自然语言处理(NLP)任务,如语言翻译、语言生成和语言理解。它们能够处理长度可变的输入序列并捕捉长距离依赖关系,使其在理解和处理自…...

OS多核多线程锁记录笔记

自旋锁作用 自旋锁的是为了保护两个核上的公共资源,也就是全局变量,只有在一方也就是一个核抢到了自选锁,才能对公共资源进行操作修改,当然还有其他形似的锁如互斥锁,这里不比较两者的区别,以前没有深入的去…...

nginx做TCP代理

要实现TCP代理,可以使用Nginx的stream模块。stream模块允许Nginx作为一个转发代理来处理TCP流量,包括TCP代理、负载均衡和SSL终止等功能。 以下是配置Nginx实现TCP代理的基本步骤: 在Nginx配置文件中添加stream块,并在该块中配置…...

python 异常处理 try

异常 我们常见的代码错误后 会出现此类异常 SyntaxError:语法错误 AttributeError:属性错误 IndexError:索引错误 TypeError:类型错误 NameError:变量名不存在错误 KeyError:映射中不存在的关键字&#xf…...

月入10万+管道收益,揭秘旅游卡运营的5个阶段!

网上的项目众多,只要用心,便能发现不少商机。在互联网上运营,关键在于理解项目的底层逻辑。今天,我们来揭秘旅游卡项目,如何做到月入10万。 1、先赚成本 开始项目时,首要任务是回本。不要急于求成&#x…...

android_binder源码分析之_binder驱动使用服务

一,binder驱动源码分析,使用服务过程 uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) {uint32_t handle;unsigned iodata[512/4];struct binder_io msg, reply;bio_init(&msg, iodata, sizeof(iodata), 4);b…...

【波点音乐看广告】

import uiautomator2 as u2 import time from datetime import datetime import xml.etree.ElementTree as ET import re import os 连接设备 d u2.connect() os.system(‘adb shell chmod 775 /data/local/tmp/atx-agent’) os.system(‘adb shell /data/local/tmp/atx-age…...

[SWPUCTF 2021 新生赛]pop

常见的魔术方法 魔术方法__construct() 类的构造函数,在对象实例化时调用 __destruct() 类的析构函数,在对象被销毁时被调用 __call() 在对象中调用一个不可访问的对象时被调用,比如一个对象被调用时,里面没有程序想调用的属性 …...

【DevOps】Jenkins + Dockerfile自动部署Maven(SpringBoot)项目

环境 docker_host192.168.0.1jenkins_host192.168.0.2 jenkins_host构建完成后把jar发布到docker_host,再通过dockerfile自动构建镜像,运行镜像 1 Jenkins安装 AWS EC2安装Jenkins:AWS EC2 JDK11 Jenkins-CSDN博客 AWS EC2上Docker安装…...

【C++】——入门基础知识超详解

目录 ​编辑 1.C关键字 2. 命名空间 2.1 命名空间定义 2.2 命名空间使用 命名空间的使用有三种方式: 注意事项 3. C输入&输出 示例 1:基本输入输出 示例 2:读取多个值 示例 3:处理字符串输入 示例 4:读…...

ChatGPT技术演进简介

chatGPT(chat generative pre-train transformer, 可以对话的预训练trasformer模型),讨论点: 1、chatGPT为什么突然火了 2、GPT 1.0、2.0、3.0、3.5 、4和4o区别和特性,在不同应用场景中如何选对模型 3、未…...

C语言 | Leetcode C语言题解之第114题二叉树展开为链表

题目: 题解: void flatten(struct TreeNode* root) {struct TreeNode* curr root;while (curr ! NULL) {if (curr->left ! NULL) {struct TreeNode* next curr->left;struct TreeNode* predecessor next;while (predecessor->right ! NULL)…...

Vue 子组件向父组件传值

1、使用自定义事件 ($emit) 这是Vue中最常用的子组件向父组件传递数据的方式。子组件通过触发一个自定义事件&#xff0c;并附加数据作为参数&#xff0c;父组件则监听这个事件并处理传递过来的数据。 子组件 (发送数据)&#xff1a; <template><button click"…...

【前端笔记】Vue项目报错Error: Cannot find module ‘webpack/lib/RuleSet‘

网上搜了下发现原因不止一种&#xff0c;这里仅记录本人遇到的原因和解决办法&#xff0c;仅供参考 原因&#xff1a;因为某种原因导致本地package.json中vue/cli与全局vue/cli版本不同导致冲突。再次提示&#xff0c;这是本人遇到的&#xff0c;可能和大家有所不同&#xff0c…...

edge浏览器的网页复制

一些网页往往禁止复制粘贴&#xff0c;本文方法如下&#xff1a; 网址最前面加上 read: &#xff08;此方法适用于Microsoft Edge 浏览器&#xff09;在此网站网址前加上read:进入阅读器模式即可...

视频播放器-Kodi

一、前言 Kodi 是一款开源免费的多媒体播放软件。Kodi 是由非营利性技术联盟 Kodi 基金会开发的免费开源媒体播放器应用程序。 Kodi是一款免费和开源&#xff08;遵循GPL协议&#xff09;的多媒体播放器和娱乐中心软件&#xff0c;由XBMC基金会开发。Kodi的主要功能是管理和播…...

Helm安装kafka3.7.0无持久化(KRaft 模式集群)

文章目录 2.1 Chart包方式安装kafka集群 5.开始安装2.2 命令行方式安装kafka集群 搭建 Kafka-UI三、kafka集群测试3.1 方式一3.2 方式二 四、kafka集群扩容4.1 方式一4.2 方式二 五、kafka集群删除 参考文档 [Helm实践---安装kafka集群 - 知乎 (zhihu.com)](https://zhuanlan.…...

【机器学习】期望最大化(EM)算法

文章目录 一、极大似然估计1.1 基本原理1.2 举例说明 二、Jensen不等式三、EM算法3.1 隐变量 与 观测变量3.2 为什么要用EM3.3 引入Jensen不等式3.4 EM算法步骤3.5 EM算法总结 参考资料 EM是一种解决 存在隐含变量优化问题 的有效方法。EM的意思是“期望最大化&#xff08;Exp…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

DBAPI如何优雅的获取单条数据

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

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...