2010-01-19 21 views
7

Tengo una aplicación .NET/C++ nativa. Actualmente, el código C++ asigna memoria en el montón predeterminado que persiste durante la vida de la aplicación. Básicamente, las funciones/comandos se ejecutan en C++ lo que da como resultado la asignación/modificación de la memoria persistente actual. Estoy investigando un enfoque para cancelar una de estas funciones/comandos a mediados de la ejecución. Tenemos cientos de estos comandos, y muchos son código muy complicado (heredado).¿Puede Win32 "mover" la memoria asignada en el montón?

El enfoque de fuerza bruta que trato de evitar es modificar cada comando/función para verificar la cancelación y hacer toda la limpieza adecuada (liberar la memoria del montón). Estoy investigando un enfoque de subprocesos múltiples en el que un subproceso adicional recibe la solicitud de cancelación y finaliza el subproceso de ejecución de comandos. Me gustaría que toda la memoria dinámica se asignara en un "montón privado" usando HeapCreate() (Win32). De esta forma, el heap privado podría ser destruido por el hilo que maneja la solicitud de cancelación. Sin embargo, si el comando se ejecuta hasta completarse, necesito que la memoria dinámica persista. En este caso, me gustaría hacer el equivalente lógico de "mover" la memoria de pila privada al montón predeterminado/de proceso sin incurrir en el costo de una copia real. ¿Es esto de alguna manera posible? ¿Esto tiene sentido?

Como alternativa, reconozco que podría tener un nuevo montón privado para cada ejecución de comando/función (cada uno será un nuevo hilo). El montón privado podría destruirse si el comando se cancela o podría sobrevivir si el comando finaliza. ¿Hay algún problema con el número de montones creciendo indefinidamente? Sé que hay algunos gastos generales involucrados con cada montón. ¿Con qué limitaciones me puedo encontrar?

Funciono en Windows 7 de 64 bits con 8GB de RAM (considere esto la plataforma de destino). La aplicación con la que estoy trabajando es de aproximadamente 1 millón de SLOC (la mitad de C++, la mitad de C#). Estoy buscando cualquier experiencia/sugerencia con gestión de pila privada, o solo alternativas a mi solución.

+0

¿Está preguntando si la memoria que asigna en un montón puede "reasignarse" a otro montón sin copiar realmente los datos? –

+0

Estoy 92% seguro de que la respuesta es no. Pero no lo suficiente como para publicarlo como respuesta. –

+6

La asignación de memoria de montón no es el único problema que tendrá con la terminación forzosa de subprocesos. La única forma segura de terminar un hilo es desde adentro. De esta forma, sabes que el hilo no está en el medio de una operación bloqueada. La interrupción debe ser una característica intrínseca de sus funciones; no es algo que puedas disparar desde el exterior. –

Respuesta

1

El montón es una especie de gran cantidad de memoria. Es un administrador de memoria de nivel de usuario. Un montón se crea mediante llamadas de memoria del sistema de nivel inferior (por ejemplo, sbrk en Linux y VirtualAlloc en Windo ws). En un montón, entonces puede solicitar o devolver un pequeño trozo de memoria mediante malloc/new/free/delete. Por defecto, un proceso tiene un solo montón (a diferencia de la pila, todos los hilos comparten un montón). Pero, puedes tener muchos montones.

  • ¿Es posible combinar dos montones w/o copia? Un montón es esencialmente una estructura de datos que mantiene una lista de fragmentos de memoria usados ​​y liberados. Por lo tanto, un montón debe tener una especie de datos contables llamados metadatos. Por supuesto, estos metadatos son por montón. AFAIK, no heap manager admite una operación de fusión de dos montones. Revisé todo el código fuente de la implementación de malloc en Linux glibc (Doug Lea's implementation), pero no hubo tal operación. Las funciones de Windows Heap * también se implementan de manera similar. Por lo tanto, actualmente es imposible mover o fusionar dos montones separados.

  • ¿Es posible tener muchos montones? No creo que deba haber un gran problema para tener muchos montones. Como dije antes, un montón es solo una estructura de datos que mantiene trozos de memoria usados ​​/ liberados. Por lo tanto, debería haber una cierta cantidad de gastos generales. Pero, no es tan severo. Cuando mira uno de malloc implementation, existe malloc_state, que es una estructura de datos básica para cada pila. Por ejemplo, puede crear otro montón por create_mspace (en Windows, es HeapCreate), luego obtendrá un nuevo estado malloc. No es tan grande. Entonces, si esta pisada (algo de sobrecarga de montón frente a facilidad de implementación) está bien, entonces puede continuar.

Si yo fuera tú, intentaré la forma en que describes. Tiene sentido para mí. Tener muchos objetos de montón no haría una gran sobrecarga.

Además, debe tenerse en cuenta que las regiones de memoria que se mueven técnicamente son imposibles. Los punteros que apuntan a la región de memoria movida darán como resultado punteros colgantes.

p.s. Su problema parece una transacción, especialmente la memoria transaccional de software. Una implementación típica de buffers STM pendientes de escritura de memoria, y luego se compromete con la memoria del sistema real, la transacción no tuvo conflicto.

+0

@STingRaySC: la asignación entre la dirección virtual y la dirección física no tiene nada que ver con este problema. Simplemente no podemos ver tal mapeo. Solo estamos considerando mover/fusionar en el espacio de direcciones virtuales.Los programadores solo pueden ver la dirección virtual (excepto algunas situaciones embeeded o de modo real). Sí, la asignación a la dirección física siempre se puede cambiar, pero está completamente oculta. Sin embargo, mover/fusionar montones de b/w se realiza solo dentro de espacios de direcciones virtuales, por lo que, en general, es imposible a menos que implementemos un mecanismo muy costoso para rastrear punteros referenciados. – minjang

1

No. La memoria no se puede mover entre montones.

4

Usted puede ser mejor con procesos separados en lugar de hilos separados:

  • uso de memoria archivos asignados (es decir, no es un archivo en absoluto - sólo cruzada procesado de memoria compartida)
  • matar a un proceso es ' limpia' que matar un hilo
  • I pensar que puede tener la memoria compartida 'sobrevivir' la matanza sin movimiento - asignar/desasignar en lugar de mover

aunque es posible que tenga que hacer algo de gestión de la memoria por su cuenta.

De todos modos, vale la pena investigar. Estaba buscando utilizar la memoria entre procesos para algunas otras cosas, y tenía algunas propiedades inusuales (puede recordarlo todo claramente, fue hace un tiempo), y es posible que pueda aprovecharlo.

¡Solo una idea!

2

Desde la página de MSDN Heap Functions: "La memoria asignada por HeapAlloc no se puede mover la dirección devuelta por HeapAlloc es válida hasta que el bloque de memoria se libera o reasignados; el bloque de memoria no necesita estar encerrado.".

¿Puede volver a vincular las aplicaciones heredadas con su propia implementación malloc()? Si es así, debería poder administrar sin modificar el resto del código.Su biblioteca malloc personalizada puede rastrear los bloques asignados por subproceso y tener una función "FreeAllByThreadId() a la que llama después de eliminar la hebra de la función heredada. Puede usar montones privados dentro de la biblioteca.

Una alternativa a montones privados podría estar haciendo su propia asignación de archivos mapeados en memoria. Consulte "Creating Named Shared Memory". Cree la memoria compartida al inicializar la biblioteca de aloc para el hilo heredado. En caso de éxito, asóciela en el hilo principal para que su C# pueda acceder a ella, al finalizar, ciérrela y se libera en el sistema

+0

GetCurrentThreadId() Windows API – tony

Cuestiones relacionadas