2010-09-10 15 views
14

Disculpas por el vasto alcance de la pregunta. Pero, ¿cuál es el factor de diseño en la gestión de la memoria en C++? Por ejemplo: ¿por qué hay una pérdida de memoria cuando un programa no libera un objeto de memoria antes de que salga? ¿No se supone que un buen diseño del lenguaje de programación debe mantener una "mesa de foo" que solucione esta situación? Sé que estoy siendo un poco ingenuo, pero ¿cuál es la filosofía de diseño de la gestión de memoria en C++ con respecto a clases, estructuras, métodos, interfaces, clases abstractas?¿Cuál es la filosofía de administrar la memoria en C++?

Sin duda, uno no puede recordar humanamente todas las especificaciones de C++. ¿Cuál es el diseño central de manejo de la memoria?

+0

Usted podría estar interesado en http://stackoverflow.com/questions/3289726/in-c-any-general-guidelines-for-handling-memory- allocation-deletion/3289929 – sellibitze

Respuesta

37

¿Cuál es el diseño central de manejo de la memoria?

En casi todos los casos, debe utilizar la administración automática de recursos. Básicamente:

  • Dondequiera que sea práctico hacerlo, prefieren crear objetos con una duración de almacenamiento automático (es decir, en la pila, o una función local)
  • Siempre debe utilizar la asignación dinámica, utilice Alcance-Bound Resource Management (SBRM, más comúnmente llamado Resource Acquisition is Initialization o RAII).

Es raro que usted tiene que escribir su propio contenedor RAII: biblioteca estándar de C++ ofrece todo un conjunto de contenedores (por ejemplo, vector y map) y punteros inteligentes como shared_ptr (de C++ TR1, C++ 0x, y Boost) funcionan muy bien para la mayoría de las situaciones comunes.

Básicamente, en muy buen código C++, nunca se debe llamar a sí mismo delete para limpiar la memoria que se ha asignado: la gestión de memoria y la limpieza de recursos siempre deben ser encapsulados en un contenedor de algún tipo.

1. Obviamente, la excepción aquí es cuando usted mismo implementa un contenedor RAII, ya que ese contenedor debe ser responsable de limpiar todo lo que posee.

+0

incluso cuando implemente un contenedor SBRM, Por lo general, prefiero basarlo en 'unique_ptr' o' scoped_ptr'. Más fácil. Además, no se debe olvidar la excelente biblioteca Boost Pointer Container, que no es tan necesaria con 'unique_ptr', pero que aún ofrece capacidades adicionales:' clone' y azúcar sintáctico con los operadores. –

+1

+1 "nunca debe llamar a eliminarse usted mismo": Esto es tan cierto, pero a menudo mal entendido. A menudo escucho la acusación: C++ no tiene un recolector de basura. Si uno sigue las pautas que enumeró, un recolector de basura es en gran medida superfluo. –

+0

Al usar la duración de almacenamiento automático usando la pila, ¿hay algún límite en el tamaño de mis datos que puedo almacenar? ¿Podría agregar, digamos, un millón de objetos de la clase "Persona" a un objeto de la clase "Nación"? ¿Qué restringe el tamaño del espacio de objetos en la pila para evitar el desbordamiento del búfer? –

2

¿por qué hay una pérdida de memoria cuando un programa no libera un objeto de memoria antes de que salga?

Bueno, el sistema operativo normalmente limpia su desorden para usted. Sin embargo, ¿qué sucede cuando su programa se ejecuta durante un período de tiempo arbitrario y ha filtrado tanta memoria que ya no puede asignar? Chocas, y eso no es bueno.

¿No se supone que un buen lenguaje de programación debe mantener un "foo-table" que solucione esta situación?

No. Algunos lenguajes de programación tienen administración de memoria automática, otros no. Hay beneficios y desventajas para ambos modelos. Los idiomas con administración de memoria manual le permiten decir cuándo y dónde se asignan y publican los recursos, es decir, es muy determinista. Sin embargo, un principiante relativo inevitablemente escribirá código que se filtra mientras se está acostumbrando a manejar la memoria.

Los esquemas automatizados son geniales para el programador, pero no se obtiene el mismo nivel de determinismo. Si estoy escribiendo un controlador de hardware, este puede no ser un buen modelo para mí.Si estuviese escribiendo una GUI simple, entonces probablemente no me preocupen si algunos objetos persisten durante un poco más de tiempo de lo necesario, por lo que tomaré un esquema de administración automatizado cada vez. Eso no quiere decir que los lenguajes de GC sean solo para tareas 'simples', algunas tareas solo requieren un control más estricto sobre sus recursos. No todas las plataformas tienen memoria de 4GB + para jugar en ella).

Existen patrones que puede usar para ayudarlo con la administración de la memoria. El ejemplo canónico sería RAII (Resource Allocation is Initialization)

+0

Sí señor !! tienes razón. Pero ¿por qué una situación así es permitida por un lenguaje de programación? ¿Este diseño es deliberado para hacer que los programadores sean poderosos o paranoicos con cada asignación de memoria que se realiza? –

+0

Se agregó más información. –

+1

@de costo: No, es más que hubo un momento en que esa "cosa mágica" llamada un recolector de basura no existía. –

3

C y C++ toman la posición que usted, el programador, sabe cuando ha terminado con la memoria que ha asignado. Esto evita la necesidad de que el tiempo de ejecución del idioma sepa mucho de lo que se ha asignado y las tareas asociadas (recuento de referencias, recolección de basura, etc.) necesarias para "limpiar" cuando sea necesario.

En el quid es la idea de que: si lo asigna, debe liberarlo. (malloc/free, new/delete)

Existen varios métodos para ayudar a administrar esto para que no tenga que recordar explícitamente. RAII y las implementaciones de puntero inteligente que proporcionan contenedores que lo hacen es extremadamente útil y potente para administrar la memoria basada en la creación y destrucción de objetos. Le ahorrarán horas de tiempo.

4

No está del todo claro si está preguntando sobre la filosofía de lo que está integrado en C++, o cómo usarlo de una manera que evite fugas de memoria.

La forma principal de evitar fugas de memoria (y otras fugas de recursos) se conoce como RAII (Inicialización de adquisición de recursos es Inicialización) o SBRM (Gestión de recursos enlazados por alcance). De cualquier manera, la idea básica es bastante simple: dado que los objetos con auto duración de almacenamiento se destruyen automáticamente al salir de su ámbito, se asigna memoria en el controlador de dicho objeto y se libera la memoria en su dtor.

En lo que se refiere a C++, realmente no tiene una filosofía. Proporciona mecanismos, pero deja en manos del programador decidir qué mecanismo es el apropiado para la situación en cuestión. Eso es a menudo RAII. A veces puede ser un recolector de basura. Otras veces, otras veces podría ser varios tipos de administradores de memoria personalizados. Por supuesto, a veces es una combinación de dos o tres, o algo completamente diferente.

Editar: En cuanto a qué C++ hace las cosas de esta manera, es bastante simple: casi cualquier otra opción hará que el lenguaje inadecuado para al menos algunos tipos de problemas - incluyendo un número del que C++ fue bastante clara intención de ser adecuado. Una de las más obvias era la posibilidad de ejecutar en una máquina "descubierta" con un mínimo de estructura de soporte (p. Ej., Sin SO)

+0

+1 - tenga en cuenta que la asignación no necesariamente tiene que suceder en el constructor; ver 'std :: auto_ptr' para un ejemplo donde no lo hace. –

1

Filosofía, creo que hay dos cosas que llevan a que C++ no tenga un recolector de basura (que parece ser lo que está recibiendo a):

  • compatibilidad con C. C++ intenta ser muy compatible con C, para mejor o peor. C no tenía recolección de elementos no utilizados, por lo que C++ no lo hace, al menos no de forma predeterminada. Supongo que podrías resumir esto como "razones históricas".

  • La filosofía de "solo paga por lo que usa". C++ intenta evitar imponer cualquier sobrecarga por encima de C a menos que lo solicite explícitamente. Así que solo pagas el precio de las excepciones si realmente lanzas una, etc. Existe un argumento de que la recolección de basura impondría un costo cada vez que se asigna un objeto en el montón, por lo que no podría ser el comportamiento predeterminado en C++.

    Tenga en cuenta que en realidad hay bastante debate sobre si la recolección de basura es en realidad más o menos eficiente que la gestión de memoria manual. Sin embargo, los mejores recolectores de basura generalmente quieren poder mover cosas, y C++ tiene una aritmética de punteros (nuevamente, heredada de C) que hace que sea muy difícil hacer que tal recopilador funcione con C++.

Aquí es la respuesta de BS (no muy directa) a "Why doesn't C++ have garbage collection?":

Si desea recolección de basura automática, hay buenos recolectores de basura de dominio público y comercial para C++. Para las aplicaciones en las que la recogida de basura es adecuada, C++ es un excelente lenguaje recogido de basura con un rendimiento que se compara favorablemente con otros lenguajes recogidos de basura. Consulte el lenguaje de programación C++ (3ª edición) para ver una discusión sobre la recolección automática de basura en C++. Ver también, Hans-J. Sitio de Boehm para la recolección de basura C y C++.

Además, C++ admite técnicas de programación que permiten que la administración de la memoria sea segura e implícita sin un recolector de basura.

C++ 0x ofrece un GC ABI.

0

¿Cuál es el diseño central de manejo de la memoria?

El diseño de conducción (sin juego de palabras) es un poco como el de los automóviles de transmisión con cambio de barra, a diferencia de los automóviles de transmisión automática. Al igual que un automóvil con palanca de cambios, C++ le da libertad y control sobre la máquina, pero no es tan fácil de usar como los automáticos que se encargan de muchas cosas para usted.

El siguiente podría fácilmente haber sido escrito sobre C++ frente Java:

Las personas que conducen vehículos caja de cambios conocen la diferencia y las ventajas de que tienen el control total de su motor del coche; las personas que conducen automóviles con transmisiones automáticas no lo hacen. (...) Los autos de carrera, por ejemplo, no usan transmisiones automáticas . (...) Las personas que están acostumbradas a cambiar de marcha se centrarán más en en su conducción, por lo que es más eficiente y segura.

http://www.eslbee.com/contrast_stick_shift_or_automatic.htm

debo añadir, sin embargo, que C++ tiene algún tipo de mecanismo que se encargan de la memoria para que, como otros han mencionado, por ejemplo, RAII, punteros inteligentes, etc.

-2

C++ no tiene filosofía de diseño wrt memory. Todo lo que tiene son dos funciones para asignar memoria (nuevo malloc) y dos funciones para liberar memoria (eliminar gratis) y una función relacionada con frew. Incluso aquellos pueden ser reemplazados por el programador.

Esto se debe a que C++ tiene como objetivo ejecutar en equipos genéricos. Las computadoras genéricas son una CPU, memoria (RAM, variedades de ROM) y un bus/bus para periféricos. No existe una gestión de memoria integrada en las computadoras genéricas.

Ahora la mayoría de las computadoras vienen con memoria (generalmente una variante ROM) que contiene una bios/monitor. Allí es posible que vea una forma rudimentaria de gestión de la memoria, probablemente no.

Algunas computadoras vienen con sistemas operativos que tendrán administración de memoria, pero incluso allí a menudo es primitivo, y es fácil para mí afirmar que la mayoría de las computadoras que ejecutan un programa C++ no tienen ningún sistema operativo.

Si espera que C++ se ejecute en cualquier computadora, no puede tener una filosofía de administración de memoria.

+0

Bueno, 'new' y' delete' son operadores, no funciones, C++ ofrece mucho más que estos para administrar la memoria (¿qué pasa con 'std :: string'?), Y la administración de memoria no es una función de un sistema operativo, sino del entorno de tiempo de ejecución de un idioma. – sbi

1

¿No se supone que un buen lenguaje de programación debe mantener un "foo-table" que solucione esta situación?

¿Lo es? ¿por qué? Un buen lenguaje de programación es aquel que le permite resolver problemas, ni más ni menos. Un recolector de basura sin duda reduce la barrera de entrada, pero también le quita el control al programador, lo que podría ser un problema en algunos casos. Es cierto que en una computadora moderna de cuatro núcleos y 2,5 GHz, y con los recolectores de basura avanzados y eficientes de hoy en día, podemos vivir con eso. Pero C++ tuvo que trabajar con un hardware mucho más limitado, desde computadoras de escritorio con 16 MB de RAM hasta plataformas integradas con 16 KB, y todo lo demás. Tiene que ser utilizable en código en tiempo real, donde puede no solo pausa el programa durante 0.5 segundos para ejecutar una recolección de basura.

C++ no solo está diseñado para ser el lenguaje utilizado en las computadoras de escritorio. Está destinado a ser utilizable en todas partes, en sistemas de memoria limitada, en escenarios duros en tiempo real, en supercomputadores grandes y en cualquier otro lugar.

El principio rector de C++ es "usted no paga por lo que no usa". Si no lo hace quiere un recolector de basura, no debería tener que pagar el precio (empinado) de uno.

Existen técnicas muy potentes para administrar la memoria en C++ y evitar pérdidas de memoria, incluso sin un recolector de basura. Si un recolector de basura fue solo manera de evitar fugas de memoria, entonces habría un fuerte argumento a favor de agregar uno al lenguaje. Pero no lo es. Solo tiene que aprender cómo administrar la memoria usted mismo en C++.

+0

¿Podría enumerar las poderosas técnicas para administrar la memoria en C++ para evitar pérdidas de memoria aparte de las enumeradas anteriormente? –

Cuestiones relacionadas