Procedimientos recomendados para administrar el uso de RAM en aplicaciones de alto nivel
Importante
Esta es la documentación de Azure Sphere (heredado). Azure Sphere (heredado) se retira el 27 de septiembre de 2027 y los usuarios deben migrar a Azure Sphere (integrado) en este momento. Use el selector de versiones situado encima de la TOC para ver la documentación de Azure Sphere (integrado).
Aunque el sistema operativo Azure Sphere usa el kernel de Linux como base, es importante recordar que todavía está escribiendo aplicaciones para un dispositivo insertado con restricciones de RAM significativas. La aplicación de buenas prácticas de programación insertadas le ayudará a crear aplicaciones confiables de Azure Sphere.
Importante
Para obtener información precisa de uso de RAM para la aplicación, es importante ejecutar la aplicación sin depurar. La ejecución de la aplicación en el depurador dará lugar a un uso de RAM inflado, ya que la RAM consumida por el servidor de depuración se incluirá en las estadísticas de uso de RAM notificadas. Para obtener más información sobre las estadísticas de memoria para la aplicación que se ejecuta en el dispositivo conectado, consulte Uso de memoria en aplicaciones de alto nivel.
Estos son algunos procedimientos recomendados que se deben seguir:
- Asigne memoria por adelantado (idealmente estáticamente) y déjela asignada durante la vigencia de la aplicación siempre que sea posible. Esto aumentará considerablemente el determinismo del uso de RAM de la aplicación y reducirá el riesgo de aumento de la superficie de memoria y la fragmentación durante la duración de la aplicación.
- Cuando la asignación dinámica es absolutamente necesaria:
- Intente minimizar la frecuencia de las asignaciones de memoria del montón y desasignaciones que realiza la aplicación para reducir los riesgos de fragmentación de memoria del montón, por ejemplo, aprovechando las técnicas de asignación de fragmentos o grupos de memoria.
- Revise las páginas de pila y, cuando sea posible, encapsula las llamadas a
malloc()
con llamadas amemset()
para forzar la confirmación de las páginas. Esto ayuda a garantizar que si una asignación hace que la aplicación supere su límite de RAM, el sistema operativo lo finalizará inmediatamente y de forma predecible. Al esperar a acceder a las páginas asignadas, se producirá el riesgo de un bloqueo retrasado fuera de memoria, lo que es más difícil de reproducir y diagnosticar. - Habilite el seguimiento de asignación de memoria del montón mientras está en modo de desarrollo.
- Evite usar
Log_Debug
con cadenas grandes y quite estas llamadas (por ejemplo, con un#ifdef
) cuando no están en modo de desarrollo.Log_Debug
hace que se asignen búferes temporales, lo que conduce a ráfagas repentinas en el uso de RAM cuando se usa con cadenas grandes. - Use eventLoop API siempre que sea posible para tareas asincrónicas periódicas (como interactuar con periféricos) en lugar de crear subprocesos. La creación de subprocesos hace que el kernel de Linux asigne memoria adicional asignada a la aplicación. Esto reduce el determinismo de la aplicación a medida que aumenta la probabilidad de que el programador del sistema operativo cambie entre varias operaciones distintas que pueden hacer que la aplicación supere su límite de RAM. Muchas de las aplicaciones de ejemplo de Azure Sphere, como la GPIO_HighLevelApp, muestran cómo usar EventLoop.
- Evite el uso prematuro de cachés de memoria para los valores que se pueden volver a calcular en tiempo de ejecución.
- Al usar libcurl:
Ajuste los tamaños máximos del búfer de socket al usar libcurl. El sistema operativo Azure Sphere asignará búferes de socket que se atribuyen al uso de RAM de la aplicación. Reducir estos tamaños de búfer puede ser una buena manera de reducir la superficie de RAM de la aplicación. Tenga en cuenta que hacer que los búferes de socket sean demasiado pequeños afectará negativamente al rendimiento de libcurl. En su lugar, ajuste los tamaños máximos del búfer para su escenario:
static int sockopt_callback(void* clientp, curl_socket_t curlfd, curlsocktype purpose) { int size = /*specify max buffer sizes here (in bytes)*/ int size_size = sizeof(size); setsockopt(curlfd, SOL_SOCKET, SO_SNDBUF, &size, &size_size); setsockopt(curlfd, SOL_SOCKET, SO_RCVBUF, &size, &size_size); return CURL_SOCKOPT_OK; } // Place the following along with other calls to curl_easy_setopt curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, &sockopt_callback);
Consulte la documentación de CURLOPT_SOCKOPTFUNCTION libcurl.
Los parámetros CURLOPT_BUFFERSIZE y CURLOPT_UPLOAD_BUFFERSIZE de nivel superior se pueden ajustar de forma similar.
Libcurl también admite la invalidación de sus funciones de memoria interna mediante
curl_global_init_mem
y pasando funciones de devolución de llamada paramalloc
,free
,realloc
,strdup
ycalloc
. Esta funcionalidad permite realizar un seguimiento de las asignaciones dinámicas o incluso modificar el comportamiento. Por ejemplo, podría asignar un grupo de memoria por adelantado y, a continuación, usar estas devoluciones de llamada para asignar memoria libcurl desde ese grupo. Puede ser una técnica eficaz para establecer límites de protección y aumentar el determinismo de la aplicación. Consulte la documentación de curl_global_init_mem libcurl para obtener más información sobre cómo usar estas devoluciones de llamada.Nota:
Este mecanismo de devolución de llamada no cubre todas las asignaciones de memoria causadas por libcurl, solo las realizadas directamente por libcurl. En concreto, no se realiza un seguimiento de las asignaciones realizadas por wolfSSL debajo.