Saltar al contenido

¿Cuáles son las diferencias entre VirtualAlloc y HeapAlloc?

Por fin después de mucho luchar ya hallamos el resultado de este contratiempo que ciertos de nuestros usuarios de este sitio han presentado. Si tienes algún detalle que compartir no dejes de compartir tu información.

Solución:

Cada API es para diferentes usos. Cada uno también requiere que use la función de desasignación / liberación correcta cuando haya terminado con la memoria.

VirtualAlloc

Una API de Windows de bajo nivel que ofrece muchas opciones, pero que es principalmente útil para personas en situaciones bastante específicas. Solo se puede asignar memoria en (editar: no 4 KB) trozos más grandes. Hay situaciones en las que lo necesita, pero sabrá cuando se encuentre en una de estas situaciones. Uno de los más comunes es si tiene que compartir la memoria directamente con otro proceso. No lo use para la asignación de memoria de uso general. Usar VirtualFree desasignar.

HeapAlloc

Asigna el tamaño de memoria que solicite, no en grandes porciones de VirtualAlloc. HeapAlloc sabe cuando necesita llamar VirtualAlloc y lo hace automáticamente. Igual que malloc, pero es solo para Windows y ofrece un par de opciones más. Adecuado para asignar fragmentos generales de memoria. Algunas API de Windows pueden requerir que use esto para asignar la memoria que les pasa, o use su complemento HeapFree para liberar memoria que te regresen.

malloc

La forma C de asignar memoria. Prefiera esto si está escribiendo en C en lugar de C ++, y desea que su código funcione, por ejemplo, también en computadoras Unix, o si alguien dice específicamente que necesita usarlo. No inicializa la memoria. Adecuado para asignar fragmentos generales de memoria, como HeapAlloc. Una API simple. Usar free desasignar. Visual C ++ malloc llamadas HeapAlloc.

nuevo

La forma de C ++ de asignar memoria. Prefiera esto si está escribiendo en C ++. También coloca un objeto u objetos en la memoria asignada. Usar delete desasignar (o delete[] para matrices). Estudio visual new llamadas HeapAlloc, y luego tal vez inicialice los objetos, dependiendo de cómo lo llame.

En los estándares recientes de C ++ (C ++ 11 y superior), si tiene que usar manualmente delete, lo estás haciendo mal y deberías usar un puntero inteligente igual que unique_ptr en lugar de. A partir de C ++ 14, se puede decir lo mismo de new (reemplazado con funciones como make_unique()).


También hay un par de otras funciones similares como SysAllocString que es posible que le digan que debe usar en circunstancias específicas.

Es muy importante comprender la distinción entre las API de asignación de memoria (en Windows) si planea usar un lenguaje que requiere administración de memoria (como C o C ++). Y la mejor manera de ilustrarlo en mi humilde opinión es con un diagrama:

ingrese la descripción de la imagen aquí

Tenga en cuenta que esta es una vista muy simplificada y específica de Windows.

La forma de entender este diagrama es que cuanto más alto en el diagrama es un método de asignación de memoria, el nivel más alto implementación que utiliza. Pero comencemos desde abajo.

Administrador de memoria en modo kernel

Proporciona todas las reservas y asignaciones de memoria para el sistema operativo, así como soporte para archivos mapeados en memoria, memoria compartida, Copiar en escrito operaciones, etc. No es directamente accesible desde el código de modo de usuario, así que lo omitiré aquí.

VirtualAlloc / VirtualFree

Estos son los nivel más bajo API disponibles desde el modo de usuario. los VirtualAlloc función básicamente invoca ZwAllocateVirtualMemory que a su vez hace un rápido syscall para ring0 para relegar el procesamiento posterior al administrador de memoria del núcleo. También es el método más rápido para reservar / asignar bloques de memoria nueva de todos los disponibles en el modo de usuario.

Pero viene con dos condiciones principales:

  • Solo asigna bloques de memoria alineados en el límite de granularidad del sistema.

  • Solo asigna bloques de memoria del tamaño que es el múltiplo de la granularidad del sistema.

Entonces qué es esto granularidad del sistema? Puede obtenerlo llamando a GetSystemInfo. Se devuelve como dwAllocationGranularity parámetro. Su valor es específico de la implementación (y posiblemente del hardware), pero en muchos sistemas Windows de 64 bits se establece en 0x10000 bytes, o 64K.

Entonces, lo que todo esto significa es que si intenta asignar, diga solo un bloque de memoria de 8 bytes con VirtualAlloc:

void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

Si tiene éxito, pAddress se alineará en el 0x10000 límite de bytes. Y aunque solicitó solo 8 bytes, el bloque de memoria real que obtendrá será el page (o algo como 4K bytes. El tamaño exacto de la página se devuelve en el dwPageSize parámetro.) Pero, además de eso, todo el bloque de memoria que abarca 0x10000 bytes (o 64K en la mayoría de los casos) desde pAddressno estar disponible para otras asignaciones. Entonces, en cierto sentido, al asignar 8 bytes, también podría estar solicitando 65536.

Entonces, la moraleja de la historia aquí no es sustituir VirtualAlloc para las asignaciones de memoria genérica en su aplicación. Debe utilizarse para casos muy concretos, como se hace con el montón debajo. (Por lo general, para reservar / asignar grandes bloques de memoria).

Utilizando VirtualAlloc incorrectamente puede conducir a una severa fragmentación de la memoria.

HeapCreate / HeapAlloc / HeapFree / HeapDestroy

En pocas palabras, el montón Las funciones son básicamente un contenedor para VirtualAlloc función. Otras respuestas aquí brindan un concepto bastante bueno. Agregaré que, en una visión muy simplista, la forma montón funciona es este:

  • HeapCreate reserva un gran bloque de memoria virtual llamando VirtualAlloc internamente (o ZwAllocateVirtualMemory ser especifico). También configura una estructura de datos interna que puede rastrear asignaciones de tamaño más pequeño dentro del bloque reservado de memoria virtual.

  • Cualquier llamada a HeapAlloc y HeapFree en realidad, no asigne / libere ninguna memoria nueva (a menos que, por supuesto, la solicitud exceda lo que ya se ha reservado en HeapCreate) pero en cambio ellos metro fuera (o commit) un gran trozo previamente reservado, al diseccionarlo en bloques de memoria más pequeños que solicita un usuario.

  • HeapDestroy a su vez llama VirtualFree que en realidad libera la memoria virtual.

Entonces todo esto hace montón Funciones candidatos perfectos para asignaciones de memoria genéricas en su aplicación. Es ideal para asignaciones de memoria de tamaño arbitrario. Pero un pequeño precio a pagar por la conveniencia del montón funciones es que introducen una ligera sobrecarga VirtualAlloc al reservar bloques de memoria más grandes.

Otra cosa buena de montón es que realmente no necesitas crear uno. Generalmente se crea para usted cuando comienza su proceso. Entonces uno puede acceder a él llamando a la función GetProcessHeap.

malloc / libre

Es un contenedor específico del idioma para montón funciones. diferente a HeapAlloc, HeapFree, etc., estas funciones funcionarán no solo si su código está compilado para Windows, sino también para otros sistemas operativos (como Linux, etc.)

Esta es una forma recomendada de asignar / liberar memoria si programa en C. (A menos que esté codificando un controlador de dispositivo en modo kernel específico).

nuevo / eliminar

Ven como un nivel alto (bien para C++) operadores de gestión de memoria. Son específicos para el C++ idioma, y ​​me gusta malloc por C, son también los envoltorios para el heap funciones. También tienen un montón de su propio código que trata C++-inicialización específica de constructores, desasignación en destructores, generar una excepción, etc.

Estas funciones son una forma recomendada de asignar / liberar memoria y objetos si programa en C++.


Por último, quiero hacer un comentario sobre lo que se ha dicho en otras respuestas sobre el uso VirtualAlloc compartir memoria entre procesos. VirtualAlloc por sí mismo no permite compartir su memoria reservada / asignada con otros procesos. Para eso uno necesita usar CreateFileMapping API que puede crear un bloque de memoria virtual con nombre que se puede compartir con otros procesos. También puede asignar un archivo en el disco a la memoria virtual para acceso de lectura / escritura. Pero ese es otro tema.

VirtualAlloc es una asignación especializada del sistema de memoria virtual (VM) del SO. Las asignaciones en el sistema VM deben realizarse con una granularidad de asignación que (la granularidad de la asignación) depende de la arquitectura. La asignación en el sistema VM es una de las formas más básicas de asignación de memoria. Las asignaciones de VM pueden tomar varias formas, la memoria no está necesariamente dedicada o respaldada físicamente en la RAM (aunque puede serlo). La asignación de VM suele ser una proposito especial tipo de asignación, ya sea porque la asignación tiene que

  • ser muy grande
  • necesita ser compartido,
  • debe estar alineado con un valor particular (razones de desempeño) o
  • la persona que llama no necesita usar toda esta memoria a la vez …
  • etc …

HeapAlloc es esencialmente lo que malloc y new ambos eventualmente llaman. Está diseñado para ser muy rápido y utilizable en muchos tipos diferentes de escenarios de una asignación de propósito general. Es el “montón” en un sentido clásico. Los montones son en realidad configurados por un VirtualAlloc, que es lo que se usa para inicialmente reservar espacio de asignación del sistema operativo. Después de que el espacio sea inicializado por VirtualAlloc, se configuran varias tablas, listas y otras estructuras de datos para mantener y controlar el funcionamiento del HEAP. Parte de esa operación consiste en dimensionar dinámicamente (aumentar y reducir) el montón, adaptar el montón a usos particulares (asignaciones frecuentes de algún tamaño), etc.

new y malloc son algo iguales, malloc es esencialmente una llamada exacta a HeapAlloc( heap-id-default ); new sin embargo, puede [additionally] configurar la memoria asignada para C ++ objetos. Para un objeto dado, C ++ almacenará vtables en el montón para cada llamador. Estos vtables son redireccionamientos para ejecución y forman parte de lo que le da a C ++ sus características OO como herencia, sobrecarga de funciones, etc.

Algunos otros métodos de asignación comunes como _alloca() y _malloca() están apilar basado; FileMappings se asignan realmente con VirtualAlloc y establecer con banderas de bits particulares que designan esas asignaciones ser de tipo FILE.

La mayoría de las veces, debe asignar la memoria de una manera que sea consistente con el uso de esa memoria;). new en C ++, malloc para C, VirtualAlloc para casos masivos o IPC.

*** Tenga en cuenta que las grandes asignaciones de memoria realizadas por HeapAlloc en realidad se envían a VirtualAlloc después de algún tamaño (un par de cientos de k o 16 MB o algo que me olvido, pero bastante grande :)).

*** EDITAR Comenté brevemente sobre IPC y VirtualAlloc, también hay algo muy interesante sobre un tema relacionado VirtualAlloc que ninguno de los que respondieron a esta pregunta ha discutido.

VirtualAllocEx es lo que un proceso puede utilizar para asignar memoria en un espacio de direcciones de un diferente proceso. Por lo general, esto se usa en combinación para obtener la ejecución remota en el contexto de otro proceso a través de CreateRemoteThread (Similar a CreateThread, el hilo simplemente se ejecuta en el otro proceso).

Comentarios y valoraciones

Finalizando este artículo puedes encontrar las notas de otros creadores, tú incluso eres capaz insertar el tuyo si lo deseas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *