【发布时间】:2014-05-24 00:20:15
【问题描述】:
我正在使用 C++ 中的 GNU ARM 工具链中的 GCC 4.8 为 Cortex M3 开发嵌入式应用程序。该应用程序使用了一些通过函数局部静态变量实例化的单例,例如(真实代码):
GlobalDataTypeRegistry& GlobalDataTypeRegistry::instance()
{
static GlobalDataTypeRegistry inst;
return inst;
}
这是在 C++ 中实现单例的经典方法。问题是,一旦我使用这种实例化,输出代码大小就会爆炸,这显然意味着编译器/链接器添加了一些服务代码以正确初始化/销毁单例对象。
这是允许重现问题的最小示例:
这将编译成 66k 的代码 (-Os):
struct A
{
A() { __asm volatile ("nop"); }
~A() { __asm volatile ("nop"); }
};
A& getA()
{
static A a;
return a;
}
int main()
{
(void)getA();
return 0;
}
这将编译成 9k 的代码 (-Os):
struct A
{
A() { __asm volatile ("nop"); }
~A() { __asm volatile ("nop"); }
};
static A a; // Extracted from the function scope
A& getA()
{
return a;
}
int main()
{
(void)getA();
return 0;
}
如果(void)getA(); 行被完全注释掉,最终的二进制大小将大约为4k。
问题是:除了从函数范围中提取静态变量之外,我还有哪些选项可以避免这个单例的额外 62k 代码?是否有任何选项可以告诉 GCC 在应用程序退出时不需要调用单例的析构函数(因为它永远不会退出)?还有其他优化方法吗?
【问题讨论】:
-
您可以使用
-S查看汇编程序,以及两个版本之间的不同之处。 (有一点不同:在第一个版本中,编译器必须防止来自不同线程的多次调用,以仍然确保对象只初始化一次。但是我无法想象会占用这么多空间。) -
在编译器无法使用线程安全原语(互斥锁)的嵌入式系统上,GCC 如何确保线程安全?
-
我不知道。也许它不支持这样的系统上的多线程。或者它本身也实现了某种机制(这可能会导致大小增加)。
标签: c++ gcc embedded singleton gnu-arm