我们有一个用ANSI C编写的项目,一般来说,内存消耗并不是什么大问题,但现在我们有一个请求,要将我们的程序安装到256 KB的RAM中。我手头上没有这个确切的平台,所以我在32位x86 Linux下编译了我的项目(因为它提供了足够多的不同工具来评估内存消耗),优化了我所能做的事情,删除了一些特性,最终我不得不得出结论:我们需要牺牲哪些特性才能在非常小的系统上运行(如果我们能够的话)。首先,我做了一项研究,linux中的内存大小究竟是多少,似乎我必须优化RSS大小,而不是VSZ。但是在linux中,即使是一个最小的程序也会打印"Hello!“第二次在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显然,这个程序将完美地运行在小型PLC上,内存为64 of。它只是linux加载了很多lib。我为这个程序生成一个地图文件,所有这些数据+ bss都来自CRT库。我需要指出的是,如果我向这个项目添加一些代码-- 10,000次"a =a+ b“或操作数组2000长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因此,我有~36 1KB的代码和~1KB的数据。在我的项目中,我不调用malloc,我使用带有包装器库的共享内存分配,以便控制分配了多少内存:
The total memory size allocated is 2052 bytes在这个框架下显然有malloc调用,如果我用我的函数替换'malloc‘调用(总结所有的alloc请求),我看到分配了内存的~2.3KB:
root@Ubuntu12-vm:/home/app/workspace/proj_sizeopt/Cmds# LD_PRELOAD=./override_malloc.so ./App
Malloc allocates 2464 bytes total现在,我运行我的项目,并看到它的消耗了600 my的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我不明白为什么它会消耗这么多内存。代码大小很小。内存分配不多。数据的大小很小。为什么需要这么多内存?I试图分析进程的映射:
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中)是,只有28 by ,其余的由共享库使用。顺便说一下,我不使用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我不看PSS,因为它在我的情况下没有任何意义,我只看RSS。
我能从这幅画中得出什么结论?如何准确地评估应用程序的内存消耗?看看这个过程的RSS大小?还是从这个大小的RSS中减去所有映射的系统库?堆/堆栈大小是什么?
我将非常感谢任何建议,笔记,内存消耗优化技术,DOs和不对极小的RAM的平台(除了明显的-保持数据和代码的数量非常小)。我也会感谢你解释为什么只有少量的代码和数据(并且没有分配太多内存)的程序在RSS中仍然消耗大量的RAM。
提前谢谢你
发布于 2015-07-13 18:48:58
..。将我们的程序安装到256 KB的RAM中。我手头上没有这个确切的平台,所以我在32位x86 Linux下编译了我的项目。
现在您看到的是,Linux平台工具对您可能需要的堆栈和堆进行了合理的假设,考虑到它现在运行在一台大型机器上,并以一组合理的库函数来满足您的需要。有些是你不需要的,但它“免费”给了你。
要在目标平台上安装256 Kb,必须为目标平台进行编译,并使用目标平台的链接器与目标平台的库(和CRT)链接。
它们会做出不同的假设,使用可能较小的图书馆足迹,对堆栈和堆空间做出更小的假设,等等。例如,为目标平台创建"Hello“并检查其在目标平台上的需求。或者使用目标平台和库的真实模拟器(不要忘记,操作系统,它在一定程度上决定了库必须做什么)。
如果它仍然太大,你必须重写或调整整个CRT和所有图书馆.
发布于 2015-07-13 19:29:52
程序需要与嵌入式设备进行编译/链接。
要获得最佳结果,请使用makefile
使用为嵌入式设备编写的“rt”库
通过makefile使用start.s文件,该文件位于执行开始的位置。
在链接器参数中使用“静态”
使用链接器参数不包含任何库,而是包含特定请求的库。
不要使用为开发机器编写的库。只使用为嵌入式设备编写的库。
不包括stdio.h等,除非专门为嵌入式设备编写
不要在信号处理程序中调用printf()。
如果可能的话,根本不要调用printf()。
相反,编写一个小的char输出函数并让它通过uart执行输出。
不要使用信号,而是使用中断。
生成的应用程序不会在您的PC上运行,但是一旦加载,将在256 k设备上运行。
不要调用睡眠(),而是编写自己的函数,该函数使用设备计时器外设、设置定时器并将设备置于断电模式。
时间中断需要将设备从断电模式中取出。
在makefile中,具体设置堆栈、堆等的大小。
让链接步骤输出一个.map文件。学习地图文件,直到你了解其中的一切。
使用特定于嵌入式设备的编译器/链接器
您可能需要包含一个函数来初始化设备上的外围设备,如时钟、uart、计时器、看门狗和代码实际使用的任何其他内置外设。
您将需要一个分配中断表的文件,并需要一个小函数来处理每个中断,即使大多数这些函数除了清除适当的中断挂起标志并从中断返回之外,什么也不做。
您可能需要一个函数来定期刷新看门狗,有条件地,这取决于主函数仍然定期循环的指示。即主函数循环和初始化函数将刷新看门狗。
https://stackoverflow.com/questions/31389894
复制相似问题