Compartilhar via


Práticas recomendadas para gerenciar o uso de RAM em aplicativos de alto nível

Embora o sistema operacional do Azure Sphere use o kernel linux como base, é importante lembrar que você ainda está gravando aplicativos para um dispositivo inserido com restrições significativas de RAM. A aplicação de boas práticas de programação inseridas ajudará você a criar aplicativos confiáveis do Azure Sphere.

Importante

Para obter informações precisas de uso de RAM para seu aplicativo, é importante que você execute seu aplicativo sem depuração. Executar seu aplicativo sob o depurador resultará em uso inflado de RAM, pois a RAM consumida pelo servidor de depuração será incluída nas estatísticas de uso de RAM relatadas. Para obter mais informações sobre estatísticas de memória para aplicativo em execução no dispositivo anexado, consulte Uso de memória em aplicativos de alto nível.

Aqui estão algumas práticas recomendadas a seguir:

  • Aloque a memória antecipadamente (idealmente estaticamente) e deixe-a alocada para o tempo de vida do aplicativo sempre que possível. Isso aumentará consideravelmente o determinismo do uso de RAM do aplicativo e reduzirá o risco de aumentos e fragmentação do volume de memória ao longo do tempo de vida do aplicativo.
  • Quando a alocação dinâmica é absolutamente necessária:
    • Tente minimizar a frequência de alocações e alocações de memória heap que estão sendo executadas pelo aplicativo para reduzir os riscos de fragmentação de memória heap, por exemplo, aproveitando técnicas de alocação de partes/pool de memória.
    • Examine páginas de pilha e, quando possível, embrulhe chamadas malloc() com chamadas para memset() forçar páginas a se comprometerem. Isso ajuda a garantir que, se uma alocação fizer com que seu aplicativo exceda seu limite de RAM, o sistema operacional o encerrará imediatamente e previsivelmente. Esperar para acessar páginas alocadas apresentará o risco de uma falha de memória atrasada, que é mais difícil de reproduzir e diagnosticar.
    • Habilite o rastreamento de alocação de memória de heap enquanto estiver no modo de desenvolvimento.
  • Evite usar Log_Debug com cadeias de caracteres grandes e remova essas chamadas (por exemplo, com um #ifdef) quando não estiver no modo de desenvolvimento. Log_Debug faz com que buffers temporários sejam alocados, levando a interrupções repentinas no uso de RAM quando usados com cadeias de caracteres grandes.
  • Use 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 ao seu aplicativo. Isso reduz o determinismo do seu aplicativo à medida que aumenta a probabilidade de o agendador do sistema operacional alternar entre várias operações distintas que podem fazer com que seu aplicativo exceda seu limite de RAM. Muitos dos aplicativos de Exemplo do Azure Sphere, como o GPIO_HighLevelApp, demonstram como usar o EventLoop.
  • Evite o uso prematuro de caches de memória para valores que podem ser recomputados em runtime.
  • Ao usar libcurl:
    • Ajuste os tamanhos máximos do buffer do soquete ao usar libcurl. O sistema operacional do Azure Sphere alocará buffers de soquete atribuídos ao uso de RAM do aplicativo. Reduzir esses tamanhos de buffer pode ser uma boa maneira de reduzir a pegada de RAM do seu aplicativo. Observe que tornar os buffers de soquete muito pequenos afetará negativamente o desempenho do libcurl. Em vez disso, ajuste os tamanhos máximos do buffer para 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);
      

      Consulte a documentação de libcurl CURLOPT_SOCKOPTFUNCTION .

      • Os parâmetros de CURLOPT_BUFFERSIZE e CURLOPT_UPLOAD_BUFFERSIZE de nível superior podem ser ajustados da mesma forma.

      • O Libcurl também dá suporte à substituição de suas funções de memória interna usando curl_global_init_mem e passando funções de retorno de chamada para malloc, free, realloc, strdupe calloc. Essa funcionalidade permite que você acompanhe as alocações dinâmicas ou até mesmo altere o comportamento. Por exemplo, você pode alocar um pool de memória antecipadamente e, em seguida, usar esses retornos de chamada para alocar memória libcurl desse pool. Essa pode ser uma técnica eficaz para definir guardrails e aumentar o determinismo do seu aplicativo. Consulte o curl_global_init_mem documentação libcurl para obter mais informações sobre como usar esses retornos de chamada.

        Nota

        Esse mecanismo de retorno de chamada não abrange todas as alocações de memória causadas pelo libcurl, somente aquelas feitas diretamente pelo próprio libcurl. Especificamente, as alocações feitas pelo wolfSSL abaixo não são rastreadas.