2012-06-11 28 views
8

tengo un struct que tiene este aspecto:la memoria usada por un std :: string

struct queue_item_t { 
    int id; 
    int size; 
    std::string content; 
}; 

Tengo un std::vector<queue_item_t> que está poblada con muchos de estos de una consulta de base de datos.

Cuando se procesa cada elemento, se lee un archivo del disco y su contenido se coloca en el miembro de cadena content. El elemento se procesa (content se analiza) y ejecuto .clear() en la cadena para no consumir toda la memoria.

Sin embargo, esto no parece liberar la memoria. Tengo cientos de miles de elementos procesados ​​y, finalmente, el uso de la memoria aumentará más de lo que está disponible y la aplicación es eliminada por Linux con "falta de memoria" como razón.

¿Cómo puedo liberar la memoria utilizada por estas cadenas?

+0

¿necesita 'content' como miembro de la estructura? Según su explicación, parece que solo se usa muy brevemente, por lo que un temporal podría ser más adecuado para la tarea. Además, ¿por qué no utilizar 'std :: queue' en lugar de' std :: vector'? –

+0

El hecho de que su estructura se llame 'queue_item_t' sugiere que el vector de ellos representa algún tipo de cola. Si ese es el caso, ¿por qué no quitas los elementos de la cola una vez que se procesan?Lo pregunto porque es posible que la solución adecuada a su problema esté en otra parte. ¡Destruirlos (y su cadena 'content') es una manera bastante segura de liberar sus recursos! Entonces solo tiene que lidiar con el hecho de que eliminar desde el principio de un vector no es eficiente, por lo tanto, use 'deque' en su lugar, o si el orden en que se procesan no importa, entonces procese en orden inverso. –

+0

@SanderDeDycker, la parte que estoy haciendo ahora es solo la segunda parte de todo el proceso; bajo operación normal, los datos nunca se leen de los archivos, sino que se recuperan de Internet y los datos se colocan directamente en la cadena 'content' de cada elemento que se ha descargado. Pero tienes razón, que bajo diferentes circunstancias, una variable temporal sería mejor. –

Respuesta

15

std :: string y std :: vector no cambian la capacidad del contenedor (=> no liberan la memoria del contenedor) en clear(). El truco a continuación con el objeto temporal se debe usar siempre que se requiera compactación (normalmente no es necesario).

my_queue_item.content.clear(); // clear 
std::string(my_queue_item.content).swap(my_queue_item.content); // compact 

código anterior se puede hacer más simple cuando se requried limpieza + compactación:

std::string().swap(my_queue_item.content); 

Algunas implementaciones de cadena se copia en escritura. Tal cadena, cuando se refiere desde más de un lugar, volvería a asignar memoria en escritura.

+0

-1 No creo que su primera oración sea precisa. ¿Cómo se sabe que no se libera memoria en 'clear'? Probablemente sea de hecho Internamente, una cadena tiene un 'char *'. Cuando asigna un valor diferente a una cadena, la anterior es reemplazada. Sin una versión de memoria, std :: string perderá memoria, lo que no ocurre. –

+7

Y C++ 11 agrega una función de miembro 'shrink_to_fit', que es una solicitud no vinculante a la implementación para hacer algo sensato. –

+4

@Luchian: 'clear' está garantizado para no reducir la' capacidad' de la cadena, por lo que prácticamente no puede liberar memoria. –

1

clear no liberará todos la memoria de la cadena (probablemente solo el búfer). Simplemente establecerá la cadena en una vacía.

Si puede llame al clear en la cadena, ¿por qué no reutilizarlo en su lugar? Por lo tanto, en lugar de crear un nuevo queue_item_t, simplemente reemplace su miembro de cadena con el nuevo valor.

0

clear no puede liberar la memoria. Establecerá lógicamente la cadena en una cadena vacía, pero puede no afectar la memoria ya asignada.

Si está leyendo más datos en el mismo queue_item_t, debería reemplazar el contenido de la cadena anterior.

¿Estás seguro de que no estás filtrando el queue_item_t?

1

Para liberar memoria que puede hacer simplemente:

my_queue_item.content = ""; 
my_queue_item.content.shrink_to_fit(); 

El método shrink_to_fit() hará muy bien la memoria libre y asignar espacio lo suficientemente pequeño como para el nuevo valor de my_queue_item.content (15 bytes para este caso).

+1

Desafortunadamente shrink_to_fit() no es vinculante, por lo que podría ser ignorado, lo que hace que parezca una función bastante inútil cuando podría haber sido muy útil. –

Cuestiones relacionadas