8

Por ejemplo, digamos que uno debe incluir una palabra clave 'eliminar' en C# 4. ¿Sería posible garantizar que nunca tendrías punteros salvajes, pero aún así poder confiar en el recolector de basura, debido a la referencia- sistema basado?¿Puede la recolección de basura coexistir con la administración de memoria explícita?

La única forma en que podría ver que posiblemente ocurra es si en lugar de referencias a ubicaciones de memoria, una referencia sería un índice de una tabla de punteros a objetos reales. Sin embargo, estoy seguro de que habría alguna condición en la que se rompería, y sería posible romper la seguridad del tipo/tener punteros colgantes.

EDITAR: No estoy hablando solo de .net. Solo estaba usando C# como ejemplo.

+0

D hace esto, está bien. http://www.digitalmars.com/d – Rayne

Respuesta

2

Con la recolección de basura, siempre que tenga una referencia referenciada al objeto, se mantendrá con vida. Con la eliminación manual no puedes garantizar eso.

Ejemplo (pseudocódigo):

obj1 = new instance; 
obj2 = obj1; 

// 

delete obj2; 
// obj1 now references the twilightzone. 

sólo para ser corto, la combinación de la gestión de memoria manual con la recogida de basura contra del propósito de GC. Además, ¿por qué molestarse? Y si realmente quiere tener control, use C++ y no C#. ;-).

+0

Una forma de combinar mmm con gc en el ejemplo anterior (¿Quiso decir obj2 = obj1?) es que la eliminación simplemente marque el objeto para su eliminación inmediata cuando el recuento de referencias vaya a 0. – quamrana

+0

@quamrana: ¿Por qué entonces molestarse en llamar eliminar? Ya no es manual si aún espera que el recuento de referencia llegue a cero. – OregonGhost

+0

No para recolección de basura generacional. Creo que hay un caso para convertir un objeto de estar sujeto a un gc generacional a un gc contado de referencia. – quamrana

1

Lo mejor que se puede obtener es una partición en dos "hemisferios" donde se gestiona un hemisferio y puede garantizar la ausencia de punteros colgantes. El otro hemisferio tiene una gestión de memoria explícita y no ofrece garantías. Estos dos pueden coexistir, pero no, no puedes dar tus fuertes garantías al segundo hemisferio. Todo lo que podría hacer es rastrear todos los punteros. Si uno se elimina, todos los demás punteros a la misma instancia podrían establecerse en cero. No hace falta decir que esto es bastante caro. Su tabla ayudaría, pero introduzca otros costos (doble indirección).

+0

O use referencias débiles para todo en el hemisferio no administrado, y promociónelos automáticamente cuando se eliminen las referencias. También es costoso, pero desplaza parte del trabajo de la eliminación, por lo que es posible que a veces sea menos costoso. –

+0

Ouch, sería bueno tener un seguimiento de puntero, pero probablemente demasiado costoso (e inútil si ya tiene recolección de basura). –

+0

Este modelo ya casi no existe si está usando C++/CLI. Puede asignar objetos no administrados en el montón C++ y objetos administrados en el montón administrado, y tener punteros entre ellos. –

3

Puede - tipo de: haga que su objeto sea desechable, y luego deséchelo usted mismo.

Es poco probable que una eliminación manual mejore el rendimiento de la memoria en un entorno administrado. Puede ayudar con los recursos no administrados, de lo que se trata es de deshacerse.

Prefiero implementar y consumir Objetos desechables más fáciles. No tengo una idea consistente y completa de cómo debería ser esto, pero administrar recursos no administrados es un dolor detallado bajo .NET.


Una idea para la implementación de eliminar: eliminar etiquetas de un objeto para la eliminación manual. En el siguiente ciclo de recolección de basura, el objeto se elimina y todas las referencias a él se establecen en nulo.

Suena genial al principio (al menos para mí), pero dudo que sea útil. Esto tampoco es particularmente seguro, por ej. otro hilo puede estar ocupado ejecutando un método miembro de ese objeto, tal método debe arrojar, p. al acceder a los datos del objeto.

+0

El .Net IDisposable 'patrón' no se usa para la administración de memoria sino para la gestión de por vida de otros recursos no administrados como manejadores de archivos, etc. Memorymanagement siempre es manejado por garbage-collector – Mendelt

+0

Mientras que Mendelt es cierto técnicamente, el .NET IDisposable pattern es exactamente para los casos en que quieres destrucción determinista. Así que sigue siendo una buena respuesta en mi opinión. – OregonGhost

+0

Para el enfoque que describa como seguro, los idiomas deberían admitir un tipo de referencia "cambiante", que sería similar a una "referencia débil" pero sin el nivel adicional de indirección. Un concepto relacionado sería una "referencia telescópica"; un tipo especial 'TelescopingObject' tendría un campo privado' BetterVersion', y cualquier referencia telescópica a 'TelescopingObject' cuyo campo' BetterVersion' fuera no nulo sería cambiado por el GC en una referencia al objeto identificado de ese modo. Esto permitiría referencias telescópicas a cadenas que se compararon y se encontraron iguales ... – supercat

0

Chris Sells también habló de esto en .NET Rocks. Creo que fue durante su primera aparición, pero el tema podría haber sido revisado en entrevistas posteriores.

0

Mi primera reacción fue: ¿Por qué no? No me puedo imaginar que lo que quieres hacer es algo tan oscuro como dejar un montón sin referencias en el montón para encontrarlo más adelante. Como si un puntero de cuatro bytes al montón fuera demasiado para mantenerlo para hacer un seguimiento de este pedazo.

Por lo tanto, el problema no es la asignación de memoria sin referencia asignada, sino la eliminación intencional de la memoria como referencia. Como la recolección de basura realiza la función de marcar la memoria libre en algún momento, parece que deberíamos ser capaces de llamar a una secuencia alternativa de instrucciones para deshacerse de este trozo de memoria en particular.

Sin embargo, el problema radica aquí:

String s = "Here is a string."; 
String t = s; 
String u = s; 
junk(s); 

Qué hacer t y u punto a? En un sistema de referencia estricto, t y u deben ser null. Esto significa que no solo debe hacer referencia contando, sino también siguiendo.

Sin embargo, puedo ver que se debe hacer con s en este punto de su código. Por lo tanto, junk puede establecer la referencia a nulo y pasarla a la barredora con una especie de código de prioridad. El gc podría activarse para una ejecución limitada y la memoria liberada solo si no es alcanzable. Por lo tanto, no podemos liberar explícitamente todo lo que alguien haya codificado para usar de alguna otra manera. Pero si s es la única referencia, entonces el fragmento se desasigna.

Por lo tanto, creo que sólo funcionaría con una limitada adhesión al explícita lado .

0

Es posible, y ya está implementado, en lenguajes no administrados como C++. Básicamente, implementa o usa un recolector de basura existente: cuando desea la administración manual de memoria, llama a new y delete como es normal, y cuando quiere recolección de basura, llama a GC_MALLOC o cualquiera que sea la función o macro para su recolector de basura.

Vea http://www.hpl.hp.com/personal/Hans_Boehm/gc/ para ver un ejemplo.

Como estaba usando C# como ejemplo, tal vez solo tenía en mente implementar la administración manual de la memoria en un lenguaje administrado, pero esto es para mostrarle que lo contrario es posible.

0

Si la semántica de la eliminación en la referencia de un objeto haría que todas las demás referencias que hacen referencia a ese objeto sean nulas, entonces podría hacerlo con 2 niveles de direccionamiento indirecto (1 más de lo que sugiere). Aunque tenga en cuenta que, si bien el objeto subyacente se destruirá, una cantidad fija de información (suficiente para mantener una referencia) debe mantenerse en vivo en el montón.

Todas las referencias que utiliza un usuario harían referencia a una referencia oculta (que presumiblemente vive en un montón) al objeto real. Al realizar alguna operación en el objeto (como llamar a un método o confiar en su identidad, como usar el operador ==), la referencia que utiliza el programador eliminaría la referencia oculta a la que apunta. Al eliminar un objeto, el objeto real se eliminará del montón, y la referencia oculta se establecerá en nulo. Por lo tanto, los programadores de referencias verían evaluar a nulo.

Sería tarea del GC eliminar estas referencias ocultas.

0

Esto ayudaría en situaciones con objetos de larga vida. La recolección de basura funciona bien cuando los objetos se usan por cortos períodos de tiempo y se les quita la referencia rápidamente. El problema es cuando algunos objetos viven durante mucho tiempo. La única forma de limpiarlos es realizar una recolección de basura con uso intensivo de recursos.

En estas situaciones, las cosas saldrían mucho más fácil si había una manera de eliminar explícitamente los objetos, o por lo menos una forma de mover un gráfico de objetos de nuevo a la generación 0.

0

Sí ... pero con algo abuso.

C# se puede abusar un poco para que esto suceda. Si está dispuesto a jugar con la clase Marshal, StructLayout y unsafe code, puede escribir su propio administrador de memoria manual.

Puede encontrar una demostración del concepto aquí: Writing a Manual Memory Manager in C#.

+0

No hay necesidad de utilizar el marshalling, realmente. Se podría definir un tipo de estructura que incluye una matriz estática de estructuras de retención de datos, y cada instancia simplemente tiene un índice en esa matriz. Tal estructura se comportaría como una referencia (una copia de la estructura accedería al mismo elemento de matriz que el original), pero el código podría asignar estructuras del conjunto y volver a colocar las estructuras liberadas en el conjunto (si la asignación inicial fue lo suficientemente grande) al tener que asignar cualquier cosa en el montón de GC de la inicialización del tipo de letra completa. – supercat

Cuestiones relacionadas