Partilhar via


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

Importante

Esta é a documentação do Azure Sphere (Legado). O Azure Sphere (Legado) 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 Azure Sphere use o kernel Linux como base, é importante lembrar que você ainda está escrevendo aplicativos para um dispositivo incorporado com restrições significativas de RAM. A aplicação de boas práticas de programação incorporada ajudará você a criar aplicativos confiáveis do Azure Sphere.

Importante

Para obter informações precisas sobre o uso da RAM para seu aplicativo, é importante que você execute seu aplicativo sem depuração. Executar seu aplicativo sob o depurador resultará em uso de RAM inflado, porque 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 executados 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 durante o tempo de vida do seu aplicativo sempre que possível. Isso aumentará consideravelmente o determinismo do uso de RAM do seu aplicativo e reduzirá o risco de aumento do espaço ocupado pela memória e fragmentação ao longo da vida útil do aplicativo.
  • Quando a atribuição dinâmica é absolutamente necessária:
    • Tente minimizar a frequência de alocações de memória de heap e deallocations 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 blocos/pool de memória.
    • Revise páginas de pilha e, quando possível, envolva chamadas com malloc() chamadas para memset() forçar páginas a confirmar. 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 de forma previsível. Esperar para acessar as páginas alocadas introduzirá o risco de uma falha de falta de memória atrasada, que é mais difícil de reproduzir e diagnosticar.
    • Habilite o rastreamento de alocação de memória de pilha 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 explosões 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 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 tempo de execução.
  • Ao usar libcurl:
    • Ajuste os tamanhos máximos de buffer de soquete ao usar libcurl. O sistema operacional Azure Sphere alocará buffers de soquete atribuídos ao uso de RAM do seu aplicativo. Reduzir esses tamanhos de buffer pode ser uma boa maneira de reduzir o espaço ocupado pela RAM do seu aplicativo. Observe que tornar os buffers de soquete muito pequenos afetará negativamente o desempenho da libcurl. Em vez disso, ajuste os tamanhos máximos de buffer 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);
      

      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.

      • A 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 memória libcurl desse pool. Esta pode ser uma técnica eficaz para definir guarda-corpos e aumentar o determinismo da sua aplicação. Consulte a documentação do curl_global_init_mem libcurl para obter mais informações sobre como usar esses retornos de chamada.

        Nota

        Este 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 pela wolfSSL por baixo não são rastreadas.