Compartilhar via


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

Importante

Esta é a documentação do Azure Sphere (herdado). O Azure Sphere (herdado) será desativado em 27 de setembro de 2027 e os usuários devem migrar para o Azure Sphere (integrado) até esse momento. Use o seletor de versão localizado acima do sumário para exibir a documentação do Azure Sphere (Integrado).

Embora o sistema operacional do Azure Sphere use o kernel do Linux como base, é importante lembrar que você ainda está escrevendo aplicativos para um dispositivo inserido com restrições significativas de RAM. A aplicação de boas práticas de programação inserida 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. A execução do aplicativo no depurador resultará em uso de RAM inflado, 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 aplicativos em execução no dispositivo conectado, consulte Uso de memória em aplicativos de alto nível.

Aqui estão algumas práticas recomendadas a serem seguidas:

  • Aloque memória antecipadamente (idealmente estaticamente) e deixe-a alocada para o tempo de vida do seu aplicativo sempre que possível. Isso aumentará muito o determinismo do uso de RAM do aplicativo e reduzirá o risco de aumento do volume de memória e fragmentação 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 desalocações de memória de heap que estão sendo executadas pelo aplicativo para reduzir os riscos de fragmentação de memória de heap, por exemplo, aproveitando técnicas de alocação de partes/pool de memória.
    • Revise as páginas da pilha e, quando possível, encapsule as chamadas para malloc() com chamadas para forçar a confirmação das memset() páginas. 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 as páginas alocadas apresentará o risco de uma falha atrasada de falta de memória, que é mais difícil de reproduzir e diagnosticar.
    • Habilite o rastreamento de alocação de memória de heap 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 intermitências repentinas no uso de RAM quando usado 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, pois 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 recalculados em runtime.
  • Ao usar libcurl:
    • Ajuste os tamanhos máximos de buffer de 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 o volume 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 de 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 CURLOPT_SOCKOPTFUNCTION libcurl.

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

      • O Libcurl também suporta a 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 a memória libcurl desse pool. Essa pode ser uma técnica eficaz para definir proteções e aumentar o determinismo de seu aplicativo. Consulte a documentação curl_global_init_mem libcurl para obter mais informações sobre como usar esses retornos de chamada.

        Observação

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