Melhores práticas para gerir a utilização de RAM em aplicações de alto nível
Embora o SO do Azure Sphere utilize o kernel do Linux como base, é importante lembrar que ainda está a escrever aplicações para um dispositivo incorporado com restrições de RAM significativas. Aplicar boas práticas de programação incorporadas irá ajudá-lo a criar aplicações fiáveis do Azure Sphere.
Importante
Para obter informações precisas de utilização da RAM para a sua aplicação, é importante que execute a sua aplicação sem depurar. A execução da aplicação no depurador resultará numa utilização de RAM inflacionada, uma vez que a RAM consumida pelo servidor de depuração será incluída nas estatísticas de utilização de RAM comunicadas. Para obter mais informações sobre as estatísticas de memória da aplicação em execução no dispositivo anexado, veja Utilização da memória em aplicações de alto nível.
Seguem-se algumas das melhores práticas a seguir:
- Aloque a memória antecipadamente (idealmente estaticamente) e deixe-a alocada para a duração da sua aplicação sempre que possível. Isto irá aumentar significativamente o determinismo da utilização da RAM da sua aplicação e reduzir o risco de aumentos de espaço de memória e fragmentação ao longo da duração da sua aplicação.
- Quando a alocação dinâmica é absolutamente necessária:
- Tente minimizar a frequência das alocações de memória dinâmica para dados e desalocação que estão a ser executadas pela aplicação para reduzir os riscos de fragmentação da memória de área dinâmica para dados, por exemplo, ao tirar partido das técnicas de alocação de segmentos/conjunto de memória.
- Reveja páginas de pilha e, sempre que possível, encapsule chamadas
malloc()
para com chamadas paramemset()
forçar a consolidação de páginas. Isto ajuda a garantir que, se uma alocação fizer com que a sua aplicação exceda o respetivo limite de RAM, o SO irá terminá-la de imediato e previsivelmente. A espera para aceder às páginas alocadas irá introduzir o risco de uma falha de memória insuficiente atrasada, o que é mais difícil de reproduzir e diagnosticar. - Ative o controlo da alocação de memória dinâmica para dados no modo de desenvolvimento.
- Evite utilizar
Log_Debug
com cadeias grandes e remova estas chamadas (por exemplo, com um#ifdef
) quando não estiver no modo de desenvolvimento.Log_Debug
faz com que as memórias intermédias temporárias sejam alocadas, levando a picos repentinos na utilização da RAM quando utilizadas com cadeias grandes. - Utilize a API EventLoop sempre que possível para tarefas assíncronas periódicas (como interagir com periféricos) em vez de criar threads. A criação de threads faz com que o kernel do Linux aloque memória adicional atribuída à sua aplicação. Isto reduz o determinismo da sua aplicação à medida que aumenta a probabilidade de o agendador do SO alternar entre várias operações distintas que podem fazer com que a aplicação exceda o limite de RAM. Muitas das aplicações de Exemplo do Azure Sphere, como a GPIO_HighLevelApp, demonstram como utilizar o EventLoop.
- Evite a utilização prematura de caches de memória para valores que podem ser recomputados no runtime.
- Ao utilizar libcurl:
Ajuste os tamanhos máximos da memória intermédia de socket ao utilizar libcurl. O SO do Azure Sphere irá alocar memórias intermédias de socket atribuídas à utilização de RAM da sua aplicação. Reduzir estes tamanhos de memória intermédia pode ser uma boa forma de reduzir a quantidade de RAM da sua aplicação. Tenha em atenção que tornar as memórias intermédias de socket demasiado pequenas afetará negativamente o desempenho da libcurl. Em vez disso, ajuste os tamanhos máximos da memória intermédia para o seu cenário:
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);
Veja a documentação CURLOPT_SOCKOPTFUNCTION libcurl.
Os parâmetros de CURLOPT_BUFFERSIZE e CURLOPT_UPLOAD_BUFFERSIZE de nível superior podem ser igualmente ajustados.
A Libcurl também suporta a substituição das respetivas funções de memória interna ao utilizar
curl_global_init_mem
e transmitir funções de chamada de retorno paramalloc
,free
,realloc
,strdup
ecalloc
. Esta funcionalidade permite-lhe controlar as alocações dinâmicas ou até mesmo alterar o comportamento. Por exemplo, pode alocar um conjunto de memória antecipadamente e, em seguida, utilizar estas chamadas de retorno para alocar memória libcurl a partir desse conjunto. Esta pode ser uma técnica eficaz para definir proteções e aumentar o determinismo da sua aplicação. Veja a documentação curl_global_init_mem libcurl para obter mais informações sobre como utilizar estas chamadas de retorno.Nota
Este mecanismo de chamada de retorno não abrange todas as alocações de memória causadas por libcurl, apenas as que são feitas diretamente pela própria libcurl. Especificamente, as dotações feitas por wolfSSL por baixo não são rastreadas.