2009-04-09 12 views
8

Estoy desarrollando Windows con DevStudio, en C/C++ no administrado.¿Llamar a _freea realmente necesario?

Quiero asignar algo de memoria en la pila en lugar del montículo porque no quiero tener que lidiar con la liberación de esa memoria de forma manual (sé de punteros inteligentes y todas esas cosas. Tengo un caso muy específico de asignación de memoria que necesito tratar), similar al uso de las macros A2W() y W2A().

_alloca hace eso, pero está en desuso. Se sugiere utilizar malloca en su lugar. Pero la documentación de _malloca dice que una llamada a ___freea es obligatoria para cada llamada a _malloca. Luego, se frustra mi propósito de usar _malloca, usaré malloc o nuevo en su lugar.

¿Alguien sabe si puedo salirse con la suya sin llamar a _freea sin fugas y cuáles son los impactos internos?

De lo contrario, terminaré usando solo la función obsoleta _alloca.

Respuesta

13

Siempre es importante llamar a _freea después de cada llamada a _malloca.

_malloca es como _alloca, pero agrega algunos controles de seguridad adicionales y mejoras para su protección. Como resultado, es posible que _malloca asigne en el montón en lugar de la pila. Si esto ocurre y no llamas a _freea, obtendrás una pérdida de memoria.

En el modo de depuración, _malloca SIEMPRE asigna en el montón, por lo que también debe liberarse.

Busque _ALLOCA_S_THRESHOLD para obtener detalles sobre cómo funcionan los umbrales, y por qué _malloca existe en lugar de _alloca, y debería tener sentido.


Editar:

Ha habido comentarios que sugieren que la persona que acaba de asignar en el montón, y el uso de punteros inteligentes, etc.

Hay ventajas para apilar las asignaciones, que _malloca que proporcionará , entonces hay razones para querer hacer esto. _alloca funcionará de la misma manera, pero es mucho más probable que cause un desbordamiento de la pila u otro problema, y ​​desafortunadamente no brinda buenas excepciones, sino que tiende a demoler el proceso. _malloca es mucho más seguro en este aspecto y te protege, pero el costo es que todavía necesitas liberar tu memoria con _freea ya que es posible (pero poco probable en el modo de lanzamiento) que _malloca elija asignar en el montón en lugar de la pila.

Si su único objetivo es evitar tener que liberar memoria, recomendaría utilizar un puntero inteligente que se encargará de liberarle la memoria a medida que el miembro salga del alcance. Esto asignaría memoria en el montón, pero estar seguro y evitar que tenga que liberar la memoria. Sin embargo, esto solo funcionará en C++; si estás usando plain ol 'C, este enfoque no funcionará.

Si está tratando de asignar en la pila por otros motivos (por lo general, el rendimiento, ya que las asignaciones de pila son muy, muy rápidas), le recomendaría usar _malloca y vivir con el hecho de que tendrá que llamar a _freea en su valores.

+1

Simplemente curioso, pero ¿por qué los votos bajos en Mitch y mis publicaciones? Me gustaría saber por qué alguien no está de acuerdo con este comentario ... especialmente si me falta algo. –

1

Para asignar memoria en la pila, simplemente declare una variable del tipo y tamaño apropiados.

+0

¿por qué el voto a favor? El cartel preguntó sobre la pila ... –

+0

No fue mi voto negativo, pero supongo que solo porque estaba preguntando específicamente sobre _alloca/_malloca, que tienen patrones de uso de pila muy diferentes a las declaraciones de variables estándar. Personalmente, también voy a votarte, porque en la mayoría de los casos, esto es lo que hago si es posible. –

+0

@Reed Copsey: gracias. –

0

Si su preocupación es tener que liberar memoria temporal, y usted sabe todo acerca de cosas como punteros inteligentes, ¿por qué no utilizar un patrón similar donde la memoria se libera cuando se sale del alcance?

template <class T> 
class TempMem 
{ 
    TempMem(size_t size) 
    { 
    mAddress = new T[size]; 
    } 

    ~TempMem 
    { 
    delete [] mAddress; 
    } 

    T* mAddress; 
} 

void foo(void) 
{ 
    TempMem<int> buffer(1024); 

    // alternatively you could override the T* operator.. 
    some_memory_stuff(buffer.mAddress); 

    // temp-mem auto-freed 
} 
3

Otro aspecto a considerar es el uso de una clase RAII para gestionar la asignación - por supuesto que sólo es útil si la macro (o lo que sea) se pueden restringir a C++.

Si desea evitar golpear al montón por motivos de rendimiento, eche un vistazo a las técnicas utilizadas por la clase de plantilla auto_buffer<> de Matthew Wilson (http://www.stlsoft.org/doc-1.9/classstlsoft_1_1auto__buffer.html). Esto se asignará en la pila a menos que la solicitud de tamaño de tiempo de ejecución exceda el tamaño especificado en el compilador, por lo que obtendrás la velocidad de asignación sin montón para la mayoría de las asignaciones (si dimensionas correctamente la plantilla), pero todo funciona correctamente si superas ese tamaño

Desde STLsoft tiene una gran cantidad de costra para hacer frente a problemas de portabilidad, es posible que desee ver en una versión más simple de auto_buffer<> que se describe en el libro de Wilson, "Imperfect C++".

Me pareció bastante útil en un proyecto integrado .

+1

+1 en la sugerencia auto_buffer <>. Básicamente está haciendo lo que _malloca hace en lugar de _alloca en Windows. Hay una marca de verificación para asegurarse de que no volará su límite de pila, y hará asignaciones de pila si es necesario en lugar de asignaciones de pila. Esto también funciona en C. –

1

Respondí esto antes, pero me perdí algo fundamental que significaba que solo funcionaba en modo de depuración. Trasladé la llamada a _malloca al constructor de una clase que se liberaría automáticamente.

En la depuración esto está bien, ya que siempre se asigna en el montón. Sin embargo, en el lanzamiento, se asigna en la pila, y al regresar del constructor, el puntero de la pila se ha restablecido y la memoria se ha perdido.

Volví y tomé un enfoque diferente, lo que resultó en una combinación de usar una macro (eurgh) para asignar la memoria y crear una instancia de un objeto que llamará automáticamente a _freea en esa memoria. Como es una macro, está asignada en el mismo marco de pila, por lo que realmente funcionará en modo de lanzamiento. Es tan conveniente como mi clase, pero un poco menos agradable de usar.

hice lo siguiente:

class EXPORT_LIB_CLASS CAutoMallocAFree 
{ 
public: 
    CAutoMallocAFree(void *pMem) : m_pMem(pMem) {} 
    ~CAutoMallocAFree() { _freea(m_pMem); } 

private: 
    void *m_pMem; 

    CAutoMallocAFree(); 
    CAutoMallocAFree(const CAutoMallocAFree &rhs); 
    CAutoMallocAFree &operator=(const CAutoMallocAFree &rhs); 
}; 

#define AUTO_MALLOCA(Var, Type, Length) \ 
    Type* Var = (Type *)(_malloca((Length) * sizeof (Type))); \ 
    CAutoMallocAFree __MALLOCA_##Var((void *) Var); 

De esta manera puedo asignar utilizando la siguiente llamada a la macro, y es liberado cuando la clase instanciada se sale del ámbito:

  AUTO_MALLOCA(pBuffer, BYTE, Len); 
      Ar.LoadRaw(pBuffer, Len); 

Mis disculpas por la publicación algo que estaba claramente mal!

0

Si está utilizando _malloca(), debe llamar al _freea() para evitar la pérdida de memoria porque _malloca() puede hacer la asignación en pila o en montón. Recurre a asignar en el montón si el tamaño dado excede el valor_ALLOCA_S_THRESHOLD. Por lo tanto, es más seguro llamar al _freea(), que no hará nada si la asignación sucedió en la pila.

Si está utilizando _alloca() que parece estar en desuso a partir de hoy; no es necesario llamar al _freea() ya que la asignación ocurre en la pila.

Cuestiones relacionadas