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

时间:2015-04-24 17:35:40

标签: c gcc

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

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

3 个答案:

答案 0 :(得分:7)

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

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

另请注意,在某些有限的情况下,GCC正在执行tail calls,然后降低堆栈使用率(因为调用者的堆栈帧在被调用者中重用)。 (另见this old question)。

您可能还会要求编译器打包一些特定的struct - s(注意,这可能会显着降低性能)。你会想要使用__attribute__((packed))之类的-fsanitize=address等等......也许还有一些type attributes等......

也许你应该阅读更多关于variable attributes的内容,因为GC技术,概念和术语可能是相关的。请参阅Garbage Collection

如果在Linux上,this answer工具也应该有用......(在调试阶段,最近GCC的-fstack-reuse=选项)。

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

您可能应该valgrind启用code generation options(在{em>添加其他优化标记,如$)。

您当然应该使用最新版本的libc 。请注意,link-time optimizations几天前已发布(2015年4月)。

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

答案 1 :(得分:3)

使用'stack frames'有一些优点,但确实使用了更多的堆栈空间来保存堆栈帧指针。

您可以告诉编译器不要使用堆栈帧。这将(通常)略微增加代码大小,但会减少使用的堆栈量。

你只能使用char和short来代替int而不是int。

这是一个糟糕的编程实践,但可以重复使用变量和数组用于多种目的。

如果某些变量集在使用时互斥,则可以将它们放在联合中。

如果函数参数列表都非常短,那么可以让编译器传递寄存器中的所有参数。 (拥有一个包含大量通用寄存器的架构确实对此有所帮助。

仅使用一个malloc,其中包含malloc类型操作所需的所有区域,以便最小化分配的内存开销量。

有很多技巧。大多数代码使代码更难以调试/维护,并且经常使代码更难以阅读

答案 2 :(得分:1)

如果可能,您可以使用-m32选项编译32位应用程序。因此,应用程序将仅占用64位系统上一半的内存。

innerView.convert (innerView.frame.origin, to: rootView)
相关问题