【发布时间】:2015-10-02 02:27:47
【问题描述】:
我们有一个用 ANSI C 编写的项目。通常内存消耗不是一个大问题,但现在我们需要将我们的程序放入 256 KB 的 RAM 中。我手头没有这个确切的平台,所以我在 32 位 x86 Linux 下编译我的项目(因为它提供了足够不同的工具来评估内存消耗),优化我可以做的,删除一些功能,最终我必须拥有结论:我们需要牺牲哪些功能才能在非常小的系统上运行(如果我们能够的话)。首先,我研究了 linux 中的内存大小到底是多少,看来我必须优化 RSS 大小,而不是 VSZ。但在 linux 中,即使是打印“Hello world!”的最小程序也是如此。每秒一次在 RSS 中消耗 285-320 KB:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
unsigned char cuStopCycle = 0;
void SigIntHandler(int signo)
{
printf("SIGINT received, terminating the program\n");
cuStopCycle = 1;
}
int main()
{
signal( SIGINT, SigIntHandler);
while(!cuStopCycle)
{
printf("Hello, World!\n");
sleep(1);
}
printf("Exiting...\n");
}
user@Ubuntu12-vm:~/tmp/prog_size$ size ./prog_size
text data bss dec hex filename
1456 272 12 1740 6cc ./prog_size
root@Ubuntu12-vm:/home/app# ps -C prog_size -o pid,rss,vsz,args
PID RSS VSZ COMMAND
22348 316 2120 ./prog_size
显然,这个程序可以在 64KB RAM 的小型 PLC 上完美运行。它只是 linux 加载了很多库。我为这个程序生成了一个映射文件,所有这些数据 + bss 都来自 CRT 库。我需要提到的是,如果我在这个项目中添加一些代码 - 10,000 次“a = a + b”或操作数组 2000 个 long int 变量,我会看到代码大小、bss 大小的差异,但最终过程的 RSS 大小是一样,不影响)
所以我把它作为基线,我想达到的点(我永远不会达到,因为我需要更多的功能,而不仅仅是每秒打印一次消息)。
所以我的项目来了,我删除了所有额外的功能,删除了所有辅助功能,删除了除基本功能之外的所有内容。有一些方法可以优化更多,但不是那么多,可以删除的已经被带走了:
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt/Cmds# ls -l App
-rwxr-xr-x 1 root root 42520 Jul 13 18:33 App
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt/Cmds# size ./App
text data bss dec hex filename
37027 404 736 38167 9517 ./App
所以我有 ~36KB 的代码和 ~1KB 的数据。我不在我的项目中调用 malloc,我使用带有包装库的共享内存分配,这样我就可以控制分配了多少内存:
The total memory size allocated is 2052 bytes
在后台显然有 malloc 调用,如果我用总结所有分配请求的函数替换“malloc”调用,我会看到分配了 ~2.3KB 的内存:
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt/Cmds# LD_PRELOAD=./override_malloc.so ./App
Malloc allocates 2464 bytes total
现在我运行我的项目并看到它消耗了 600KB 的 RAM。
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt# ps -C App -o pid,rss,vsz,args
PID RSS VSZ COMMAND
22093 604 2340 ./App
我不明白为什么它会吃掉这么多内存。代码量很小。分配的内存不多。数据量很小。为什么会占用这么多内存?我试着分析了进程的映射:
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt# pmap -x 22093
22093: ./App
Address Kbytes RSS Dirty Mode Mapping
08048000 0 28 0 r-x-- App
08052000 0 4 4 r---- App
08053000 0 4 4 rw--- App
09e6a000 0 4 4 rw--- [ anon ]
b7553000 0 4 4 rw--- [ anon ]
b7554000 0 48 0 r-x-- libpthread-2.15.so
b756b000 0 4 4 r---- libpthread-2.15.so
b756c000 0 4 4 rw--- libpthread-2.15.so
b756d000 0 8 8 rw--- [ anon ]
b7570000 0 300 0 r-x-- libc-2.15.so
b7714000 0 8 8 r---- libc-2.15.so
b7716000 0 4 4 rw--- libc-2.15.so
b7717000 0 12 12 rw--- [ anon ]
b771a000 0 16 0 r-x-- librt-2.15.so
b7721000 0 4 4 r---- librt-2.15.so
b7722000 0 4 4 rw--- librt-2.15.so
b7731000 0 4 4 rw-s- [ shmid=0x70000c ]
b7732000 0 4 4 rw-s- [ shmid=0x6f800b ]
b7733000 0 4 4 rw-s- [ shmid=0x6f000a ]
b7734000 0 4 4 rw-s- [ shmid=0x6e8009 ]
b7735000 0 12 12 rw--- [ anon ]
b7738000 0 4 0 r-x-- [ anon ]
b7739000 0 104 0 r-x-- ld-2.15.so
b7759000 0 4 4 r---- ld-2.15.so
b775a000 0 4 4 rw--- ld-2.15.so
bfb41000 0 12 12 rw--- [ stack ]
-------- ------- ------- ------- -------
total kB 2336 - - -
看起来程序大小(在 RSS 中)只有 28KB,其余部分由共享库消耗。顺便说一句,我不使用 posix 线程,我没有显式链接到它,但是链接器无论如何都会链接这个库,我不知道为什么(这并不重要)。如果我们更详细地查看映射:
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt# cat /proc/22093/smaps
08048000-08052000 r-xp 00000000 08:01 344838 /home/app/workspace/proj_sizeopt/Cmds/App
Size: 40 kB
Rss: 28 kB
Pss: 28 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 28 kB
Private_Dirty: 0 kB
Referenced: 28 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
...
09e6a000-09e8b000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
Rss: 4 kB
Pss: 4 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
Referenced: 4 kB
Anonymous: 4 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
...
b7570000-b7714000 r-xp 00000000 08:01 34450 /lib/i386-linux-gnu/libc-2.15.so
Size: 1680 kB
Rss: 300 kB
Pss: 7 kB
Shared_Clean: 300 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 300 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
...
b7739000-b7759000 r-xp 00000000 08:01 33401 /lib/i386-linux-gnu/ld-2.15.so
Size: 128 kB
Rss: 104 kB
Pss: 3 kB
Shared_Clean: 104 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 104 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
...
bfb41000-bfb62000 rw-p 00000000 00:00 0 [stack]
Size: 136 kB
Rss: 12 kB
Pss: 12 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 12 kB
Referenced: 12 kB
Anonymous: 12 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
- 所以我看到我的项目的 RSS 大小是 40KB,但只使用了 28 KB。这是否意味着该项目将适合 256 KB 的 RAM?
- 堆大小为132KB,但只使用了4 KB。这是为什么?我相信在小型嵌入式平台上会有所不同。
- 堆栈为 136KB,但仅使用 12KB。
- GLIBC/LD 显然会消耗一些内存,但在嵌入式平台上它究竟是什么内存?
我不看 PSS,因为它对我来说没有任何意义,我只看 RSS。
我可以从这张图片中得出什么结论?如何准确评估应用程序的内存消耗?看进程的RSS大小?或者从所有映射系统库的这个大小的 RSS 中减去?堆/堆栈大小是多少?
对于 RAM 量极少的平台,我将非常感谢任何建议、注释、内存消耗优化技术、DO 和 DON'T(除了明显的 - 将数据和代码量保持在最低限度)。 我也将感谢您解释为什么具有少量代码和数据(并且不分配太多内存)的程序仍然在 RSS 中消耗大量 RAM。
提前谢谢你
【问题讨论】:
-
尽管付出了努力,但我发现很难理解这个问题..
-
没有代码可以查看。代码的第一个 sn-p 仅用于演示目的。主要问题是关于内存消耗。如何了解应用程序的实际大小以及如何减少应用程序的占用空间
-
如果自己很容易弄清楚我就不会问了;)
-
我想展示我为解决问题所做的努力。我不只是来问“我的应用程序的大小是多少”或“如何优化它”。我正在提供细节,我花时间学习这些细节,以便它可以帮助其他开发人员(希望如此)。但我仍然有疑问,这就是我在这里问的原因
标签: c memory memory-management rss