ponen - donde van los archivos dll windows 7
Obligar a Windows a cargar archivos DLL en lugares para que la memoria esté mínimamente fragmentada (3)
Mi aplicación necesita mucha memoria y una gran estructura de datos para realizar su trabajo. A menudo, la aplicación necesita más de 1 GB de memoria y, en algunos casos, mis clientes realmente necesitan utilizar la versión de 64 bits de la aplicación porque tienen varios gigabytes de memoria.
En el pasado, podía explicar fácilmente al usuario que si la memoria alcanzaba entre 1.6 y 1.7 GB de uso de memoria, estaba "sin memoria" o muy cerca de una situación de "falta de memoria", y que necesitaban reducir su memoria o pasar a una versión de 64 bits.
El año pasado noté que a menudo la aplicación solo usa alrededor de 1 GB antes de que ya se quede sin memoria. Después de algunas investigaciones, parece que la causa de este problema es la fragmentación de la memoria. Usé VMMAP (una utilidad SysInternals) para ver el uso de la memoria de mi aplicación y vi algo como esto:
Las áreas naranja son memoria asignada por mi aplicación. Las áreas púrpuras son código ejecutable.
Como puede ver en la mitad inferior de la imagen, las áreas púrpuras (que son las DLL) se cargan en muchas direcciones diferentes, lo que hace que mi memoria se fragmente. Esto no es realmente un problema si mi cliente no tiene una gran cantidad de datos, pero si mi cliente tiene conjuntos de datos que ocupan más de 1 GB, y una parte de la aplicación necesita un gran bloque de memoria (por ejemplo, 50 MB), puede dar como resultado una falla de asignación de memoria, causando que la aplicación se cuelgue.
La mayoría de mis estructuras de datos están basadas en STL y, a menudo, no requieren grandes porciones de memoria contigua, pero en algunos casos (por ejemplo, cadenas muy grandes), es realmente necesario tener un bloque contiguo de memoria. Desafortunadamente, no siempre es posible cambiar el código para que no necesite un bloque de memoria contiguo.
Las preguntas son:
- ¿Cómo puedo influir en la ubicación donde se cargan las DLL en la memoria, sin utilizar explícitamente REBASE en todas las DLL en la computadora del cliente, o sin cargar todas las DLL explícitamente?
- ¿Hay alguna manera de especificar las direcciones de carga de las DLL en su propio archivo de manifiesto de la aplicación?
- ¿O hay una manera de decirle a Windows (a través del archivo de manifiesto?) Que no distribuya la DLL (creo que esta dispersión se llama ASLR).
Por supuesto, la mejor solución es a la que puedo influir desde el archivo de manifiesto de mi aplicación, ya que confío en la carga automática / dinámica de DLL por parte de Windows.
Mi aplicación es una aplicación de modo mixto (administrado + no administrado), aunque la mayor parte de la aplicación no está administrada.
¿Alguna sugerencia?
En primer lugar, la fragmentación de su espacio de direcciones virtuales no debe necesariamente causar la condición de falta de memoria. Este sería el caso si su aplicación tuviera que asignar bloques de memoria contiguos del tamaño apropiado. De lo contrario, el impacto de la fragmentación debería ser menor.
Usted dice que la mayoría de sus datos están "basados en STL", pero si, por ejemplo, asigna un std::vector
enorme, necesitará un bloque de memoria contiguo.
AFAIK no hay forma de especificar la dirección de mapeo preferida de la DLL cuando se carga. De modo que solo hay dos opciones: volver a establecer la base (el archivo DLL) o implementar DLL cargándose usted mismo (lo cual no es trivial, por supuesto).
Por lo general, no es necesario volver a establecer la base de las DLL estándar de la API de Windows, ya que se cargan en su espacio de direcciones de forma muy precisa. La fragmentación puede llegar desde algunos DLL de terceros (como ganchos de Windows, inyecciones de antivirus, etc.)
No se puede hacer esto con un manifiesto, se debe hacer con la opción del vinculador / BASE. Linker + Advanced + Base address en el IDE. La forma más flexible es usar el / BASE: @ nombre de archivo, la sintaxis de la clave para que el vinculador lea la dirección base de un archivo de texto.
La mejor manera de llenar el archivo de texto es desde la ventana Debug + Windows + Modules. Obtenga la versión Release del programa cargado en el depurador y cargue todo el shebang. Depurar + Romper todo, abre la ventana y copia y pega en el archivo de texto. Edítelo para que coincida con el formato requerido, calculando las direcciones de carga desde la columna Dirección. Deje suficiente espacio entre los archivos DLL para que no tenga que modificar constantemente el archivo de texto.
Si puede ejecutar parte de su propio código antes de que se carguen las bibliotecas en cuestión, puede reservar una buena porción de espacio de direcciones antes de asignarlo.
De lo contrario, debe identificar las DLL responsables para determinar por qué se están cargando. Por ejemplo, ¿son parte de .NET, la biblioteca de tiempo de ejecución del lenguaje, su propio código o las bibliotecas de terceros que está utilizando?
Para su propio código, la solución más sensata es usar enlaces estáticos en lugar de dinámicos. Esto también debería ser posible para el tiempo de ejecución del idioma y puede ser posible para bibliotecas de terceros.
Para las bibliotecas de terceros, puede pasar de usar carga implícita a carga explícita, de modo que la carga solo tenga lugar una vez que haya reservado su porción de espacio de direcciones.
No sé si hay algo que puedas hacer sobre las bibliotecas .NET; pero como la mayoría de su código no está administrado, es posible eliminar los componentes administrados para deshacerse de .NET. O tal vez podría dividir las partes .NET en un proceso separado.