Поделиться через


Рекомендации по управлению использованием ОЗУ в высокоуровневых приложениях

Внимание

Это документация по Azure Sphere (устаревшая версия). Служба Azure Sphere (устаревшая версия) выходит на пенсию 27 сентября 2027 г., и к этому времени пользователи должны перейти в Azure Sphere (интегрированная). Используйте селектор версий, расположенный над toC, чтобы просмотреть документацию по Azure Sphere (интегрированная).

Хотя ОС Azure Sphere использует ядро Linux в качестве базы, важно помнить, что вы по-прежнему пишете приложения для внедренного устройства со значительными ограничениями ОЗУ. Применение хороших внедренных методик программирования поможет вам создавать надежные приложения Azure Sphere.

Внимание

Чтобы получить точные сведения об использовании ОЗУ для приложения, важно запустить приложение без отладки. Запуск приложения под отладчиком приведет к тому, что потребление ОЗУ, используемое сервером отладки, будет включено в статистику использования ОЗУ. Дополнительные сведения о статистике памяти для приложений, работающих на подключенном устройстве, см. в разделе "Использование памяти" в высокоуровневых приложениях.

Ниже приведены некоторые рекомендации.

  • Выделите память заранее (в идеале статически) и оставьте ее выделенной для времени существования приложения всякий раз, когда это возможно. Это значительно увеличит детерминированность использования ОЗУ приложения и уменьшит риск увеличения объема памяти и фрагментации в течение времени существования приложения.
  • Если динамическое выделение абсолютно необходимо:
    • Попробуйте свести к минимуму частоту выделения памяти кучи и распределения сделок, выполняемых приложением, чтобы снизить риски фрагментации памяти кучи, например путем использования методов выделения блоков или пула памяти.
    • Просмотрите страницы стека и по возможности заключите вызовы к malloc() вызовам, чтобы memset() принудительно зафиксировать страницы. Это помогает убедиться, что если выделение приводит к превышению предела ОЗУ приложения, ос будет немедленно и прогнозно прервать его. Ожидание доступа к выделенным страницам приведет к риску отложенного сбоя вне памяти, что труднее воспроизвести и диагностировать.
    • Включите отслеживание выделения памяти кучи в режиме разработки.
  • Избегайте использования Log_Debug с большими строками и удаляйте эти вызовы (например, с параметром ) #ifdef, если не в режиме разработки. Log_Debug приводит к выделению временных буферов, что приводит к внезапным всплескам использования ОЗУ при использовании больших строк.
  • Используйте API EventLoop всякий раз, когда это возможно для периодических асинхронных задач (например, взаимодействия с периферийными устройствами) вместо создания потоков. Создание потоков приводит к тому, что ядро Linux выделяет дополнительную память, связанную с приложением. Это снижает детерминацию приложения, так как она увеличивает вероятность переключения планировщика ОС между несколькими, различными операциями, которые могут привести к превышению предела ОЗУ приложения. Многие из примеров приложений Azure Sphere, таких как GPIO_HighLevelApp, демонстрируют, как использовать EventLoop.
  • Избегайте преждевременного использования кэшей памяти для значений, которые можно перекомпилировать в среде выполнения.
  • При использовании libcurl:
    • Настройте максимальный размер буфера сокета при использовании libcurl. ОС Azure Sphere выделяет буферы сокетов, которые относятся к использованию ОЗУ приложения. Уменьшение этих размеров буфера может быть хорошим способом уменьшить объем ОЗУ приложения. Обратите внимание, что слишком малые буферы сокетов негативно влияют на производительность libcurl. Вместо этого настройте максимальный размер буфера для вашего сценария:

          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);
      

      См. документацию по CURLOPT_SOCKOPTFUNCTION libcurl.

      • Параметры CURLOPT_BUFFERSIZE более высокого уровня и CURLOPT_UPLOAD_BUFFERSIZE можно настроить аналогичным образом.

      • Libcurl также поддерживает переопределение своих внутренних функций памяти с помощью curl_global_init_mem и передачи функций обратного вызова для malloc, , freeи callocreallocstrdup. Эта функция позволяет отслеживать динамические выделения или даже изменять поведение. Например, можно выделить пул памяти заранее, а затем использовать эти обратные вызовы для выделения памяти libcurl из этого пула. Это может быть эффективным способом настройки охранников и повышения детерминизма приложения. Дополнительные сведения об использовании этих обратных вызовов см. в документации по curl_global_init_mem libcurl.

        Примечание.

        Этот механизм обратного вызова не охватывает все выделения памяти, вызванные libcurl, только те, которые выполняются непосредственно libcurl. В частности, выделения, сделанные волкомSSL под ней, не отслеживаются.