27 de septiembre de 2007

Memoria perdida en método inline

Cierto día estaba yo programando un módulo en un programa de C++. Y casualmente tenía a mi disponibilidad una clase con funcionalidad que me venía muy bien. Esta clase seguía el patrón Singleton, así que obtengo un puntero al objeto Singleton y me dispuse a usarlo. Sorprendido me quede cuando de repente observo un incremento de 50 kilobytes en el tamaño del ejecutable. ¿Como puede ser?. En ese momento no lo sabía pero con un breve vistazo a como se implementaba el Singleton, empecé a sospechar lo que pasaba. El siguiente código esta en un fichero .h.
class ClassA
{
public:
static ClassA* Instance();
};

inline ClassA* ClassA::Instance()
{
static ClassA instance;
return &instance;
}
El tamaño de una instancia de la clase ClassA es aproximadamente 50 kilobytes. Y aunque el Singleton ya se ha llamado varias veces en otras parte del programa, compruebo que con cada nueva llamada el ejecutable se incrementa en otros 50 kilobytes. Bueno concretamente el compilador genera un nuevo Singleton en cada unidad de compilación (o fichero .obj en nuestro caso). Y todo esto por culpa de meter una variable estática en un método estático.

Mi solución
class ClassA
{
public:
static ClassA& Instance();

private:
static ClassA s_singleton;
};

inline ClassA& ClassA::Instance()
{
return ClassA::s_singleton;
}
Y en un fichero .cpp escribimos lo siguiente.
ClassA ClassA::s_singleton;
La solución que propongo es simplemente sacar la variable estática del método inline. De esta manera solo se creara una instancia del Singleton. Y como ventaja adicional, tenemos un código más elegante.

No todos los compiladores cometen este error, pero desafortunadamente con el que estaba trabajando en este momento si. Fue una suerte dar con este problema. Hicimos una revisión de todo el código, comprobamos que el mismo error se cometía en casí todos los Singleton, lo arreglamos y nos permitio ahorrar casi 600 kilobytes.