我正在用C++中的GNU ARM工具链为Cortex M3和GCC 4.8开发一个嵌入式应用程序。应用程序使用一些通过函数局部静态变量实例化的singleton,比如(真实代码):
GlobalDataTypeRegistry& GlobalDataTypeRegistry::instance()
{
static GlobalDataTypeRegistry inst;
return inst;
}
这是在C++中实现singleton的经典方法。问题是,一旦我使用这样的实例化,输出代码的大小就会爆炸,这显然意味着编译器/链接器添加了一些服务代码,用于对singleton对象进行正确的初始化/销毁。
以下是允许重现问题的最小示例:
这将编译成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,在应用程序退出时没有必要调用单例的析构函数(因为它永远不会退出)?还有其他优化方法吗?
将-fno-threadsafe-statics
选项添加到g++
命令中,代码大小将减小。
这是我的示例代码:
class X {
private:
X() { };
public:
~X() { };
static X* get_instance() {
static X instance;
return &instance;
}
void show() {
asm("");
}
};
int main() {
X* temp = X::get_instance();
temp->show();
while (true) {
asm("");
}
}
参考文献:
- http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html
- http://arkaitzj.wordpress.com/2009/11/07/static-locals-and-threadsafety-in-g/
您可以在用std::aligned_storage实现的缓冲区内创建新的单例。