如何针对内存使用优化GCC编译?

syn*_*gma 3 c gcc

我正在开发一个应尽可能少使用内存的库(我不关心其他任何东西,比如二进制大小或速度优化).

我可以使用任何GCC标志(或任何其他与GCC相关的选项)吗?我应该避免某种程度的-O*优化吗?

Bas*_*tch 8

你的库 - 或者惯用的C-中的任何代码都有几种内存使用方式:

  • 二进制代码大小,确实-Os应该优化它
  • 堆内存,使用C动态分配,即malloc; 你显然应该知道如何分配堆内存(以及后来的free-d).实际的内存消耗将取决于您的特定malloc实现(例如,许多实现,当调用malloc(25)实际上可能消耗32个字节),而不是在编译器上.顺便说一句,您可能会设计您的库以使用一些内存池,甚至可以实现您自己的分配器(在OS系统调用之上,如mmap上面malloc等等)
  • 局部变量,即调用堆栈上的调用.这主要取决于您的代码(但是优化编译器,例如-Os或者-O2用于gcc,可能会使用更多寄存器,并且在优化时可能会略微减少堆栈).您可以通过-fstack-usagegcc要求它给出每个调用帧的大小,并且当调用帧超过len个字节时,您可能会给-Wstack-usage=len一个警告.
  • 全局或静态变量.您应该知道他们需要多少内存(您可能会使用nm或其他一些binutils程序来查询它们).顺便说一下,在函数内部仔细地声明一些变量static会降低堆栈消耗(但是你不能对每个变量或每个函数都这样做).

另请注意,在某些有限的情况下,GCC正在进行尾调用,然后降低堆栈使用率(因为调用者的堆栈帧在被调用者中重用).(另见这个老问题).

您可能还会要求编译器打包一些特定的struct-s(注意,这可能会显着降低性能).你会想要使用某些类型属性,比如__attribute__((packed))......等等,也许还有一些变量属性 ......

也许您应该阅读有关垃圾收集的更多信息,因为GC技术,概念和术语可能是相关的.看到这个答案.

如果在Linux上,valgrind工具也应该是有用的......(在调试阶段-fsanitize=address,最近的GCC选项).

您可能也可能使用一些代码生成选项,-fstack-reuse=-fshort-enums-fpack-struct-fstack-limit-symbol=-fsplit-stack; 要非常小心:一些这样的选项会使您的二进制代码与现有的C(和其他!)库不兼容(那么您可能需要使用libc相同的代码生成标志重新编译所有使用过的库,包括您的库).

你或许应该启用链接时优化编译和链接-flto(在另外的其他优化标志一样-Os).

你当然应该使用最新版本的GCC.请注意,GCC 5.1已于几天前发布(2015年4月).

如果您的库足够大,值得付出努力,您甚至可以考虑使用MELT自定义GCC编译器(以帮助您了解如何减少内存消耗).这可能需要数周或数月的工作.