You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言静态链接下内存使用异常问题排查

静态链接内存占用实验疑问与解答

实验背景

我正在学习静态链接与动态链接,了解到静态链接相比动态链接会占用更多内存与磁盘空间,磁盘占用的差异已通过可执行文件大小验证,但在验证内存占用时出现异常,因此设计了如下实验:

实验步骤

  1. 创建名为mylib.c的C文件
//mylib.c
#include <unistd.h>

// 该函数用于生成庞大的.text段
void many_code() {
    asm volatile (
       "movabs $0x1122334455667788, %%rax \n\t"
       "movabs $0x1122334455667788, %%rax \n\t"
       "movabs $0x1122334455667788, %%rax \n\t"  // 该行重复一百万次
       ...
       ::: "rax"
    );
    sleep(-1);
}
  1. 编译目标文件
    执行命令:gcc -c mylib.c -o mylib.o

  2. 创建静态库
    执行命令:ar -r libmy.a mylib.o

  3. 创建名为use_st_lib.c的C文件

// use_st_lib.c
extern void many_code();

int main() {
   many_code();
   return 0;
}
  1. 生成静态链接可执行文件
    执行命令:gcc use_st_lib.c -static libmy.a -o use_st_lib_0

  2. 生成第二个静态链接可执行文件
    重复步骤5,生成use_st_lib_1

执行ls -hl的结果:

➜  static git:(master) ✗ ls -hl
total 91M
-rw-r--r-- 1 root root 9.6M May 29 09:37 libmy.a
-rw-r--r-- 1 root root  51M May 27 23:33 mylib.c
-rw-r--r-- 1 root root 9.6M May 29 09:37 mylib.o
-rwxr-xr-x 1 root root  11M May 29 10:11 use_st_lib_0
-rwxr-xr-x 1 root root  11M May 29 10:12 use_st_lib_1
-rw-r--r-- 1 root root   76 May 27 22:10 use_st_lib.c
  1. 监控内存使用
    在另一个终端执行top命令,设置刷新时间1.0s,过滤COMMAND=use_st_lib,初始输出:
top - 10:21:59 up 15 days, 17:40,  4 users,  load average: 0.00, 0.01, 0.05
Tasks:  79 total,   1 running,  78 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.0 us,  1.0 sy,  0.0 ni, 98.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1756.5 total,    793.8 free,    133.2 used,    829.5 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   1469.8 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND 
  1. 启动第一个进程
    执行./use_st_lib_0 &后台启动进程,此时top输出:
top - 10:31:06 up 15 days, 17:49,  4 users,  load average: 0.07, 0.06, 0.06
Tasks:  80 total,   1 running,  79 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1756.5 total,    793.6 free,    133.1 used,    829.8 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   1469.9 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND          
31239 root      25   5   10.6m   9.5m   9.5m S  0.0  0.5   0:00.00 use_st_lib_0
  1. 启动第二个进程
    执行./use_st_lib_1 &后台启动第二个进程,此时top输出:
top - 10:32:02 up 15 days, 17:50,  4 users,  load average: 0.03, 0.05, 0.05
Tasks:  81 total,   1 running,  80 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  1.0 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1756.5 total,    793.3 free,    133.4 used,    829.9 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.   1469.6 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND          
31309 root      25   5   10.6m   9.5m   9.5m S  0.0  0.5   0:00.00 use_st_lib_1     
31239 root      25   5   10.6m   9.5m   9.5m S  0.0  0.5   0:00.00 use_st_lib_0

疑问列表

  1. 为何静态链接的程序在top命令中显示有SHR(共享内存)占用?我原本预期该数值为0。
  2. 启动use_st_lib_0后,RES(驻留内存)显示占用9.5m,但top顶部的总内存使用量未如预期从133.2变为123.7。
  3. 启动use_st_lib_1后,top顶部的总内存使用量仍几乎无变化,与预期从123.7变为114.2不符。
  4. 我的实验步骤存在哪些错误,或是对静态链接内存占用的理解有偏差?

问题解答

1. 静态链接程序为何有SHR占用?

静态链接的可执行文件并非完全没有共享内存。Linux内核会共享程序中只读且可执行的段(比如.text段),即使是静态链接的程序,只要多个进程的.text段内容完全一致(比如你生成的use_st_lib_0和use_st_lib_1),内核就会通过页表映射让它们共享物理内存页,避免重复加载。此外,静态链接的程序也可能依赖内核提供的vDSO(虚拟动态共享对象,用于快速系统调用),这部分也会被计入SHR。

2. RES显示占用9.5m但总内存使用无明显变化?

top顶部的used内存统计包含buff/cache,而进程的RES是实际驻留在物理内存中的字节数,但其中可能有部分属于共享页(比如.text段),这部分内存会被多个进程重复统计,但实际物理内存只占用一份。另外,你的进程启动后调用sleep(-1)进入休眠,内核可能会将部分不常用的内存页置换到缓存区,而不是立即从free内存中扣除,导致top顶部的used数值变化不明显。可以查看/proc/<pid>/smaps文件,其中的Private_Dirty字段才是进程独占的物理内存,更能反映进程实际占用的非共享内存。

3. 启动第二个进程后总内存使用无变化?

因为两个静态链接的程序.text段完全一致,内核会让它们共享这部分物理内存,不需要重新加载一份到内存中。只有进程的私有数据段(比如.data、.bss)才会占用新的物理内存,但你的程序几乎没有私有数据,所以总内存使用量几乎不变。这也解释了为什么两个进程的SHR都等于RES——它们的所有驻留内存都是共享的只读段。

4. 实验步骤与理解偏差

  • 理解偏差:静态链接的程序并非所有内存都不共享,只读可执行段会被内核自动共享,这是Linux内存管理的优化机制,目的是减少物理内存浪费。你之前认为静态链接程序完全不共享内存是错误的。
  • 实验设计问题:你的程序中几乎没有私有可写数据段(.data/.bss),所有大内存都是只读的.text段,导致多个进程可以完全共享这部分内存,无法体现静态链接在私有内存占用上的劣势。如果要验证静态链接的内存占用问题,应该设计包含大量私有可写数据的实验,比如在静态库中定义一个大的全局数组并初始化,这样每个进程都会拥有自己的副本,此时总内存使用量才会随着进程数量增加而线性增长。

内容的提问来源于stack exchange,提问作者Michael Coleman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:20:39