管理高级应用程序中的 RAM 使用情况的最佳做法

尽管 Azure Sphere OS 使用 Linux 内核作为基础,但请务必记住,你仍在为具有重要 RAM 约束的嵌入式设备编写应用程序。 应用良好的嵌入式编程实践将有助于创建可靠的 Azure Sphere 应用程序。

重要

若要获取应用程序的准确 RAM 使用情况信息,请务必 在不调试的情况下 运行应用。 在调试器下运行应用将导致 RAM 使用率过高,因为调试服务器使用的 RAM 将包含在报告的 RAM 使用情况统计信息中。 有关在附加设备上运行的应用程序的内存统计信息的详细信息,请参阅 高级应用程序中的内存使用

下面是要遵循的一些最佳做法:

  • 预先分配内存 (理想情况下静态) ,并尽可能在应用程序的生存期内分配内存。 这将大大提高应用程序的 RAM 使用率的确定性,并降低在应用程序生存期内内存占用增加和碎片的风险。
  • 绝对需要动态分配时:
    • 尝试将应用程序正在执行的堆内存分配和解除分配的频率降到最低,以降低堆内存碎片的风险,例如,利用区块分配/内存池技术。
    • 查看堆栈页,如果可能,使用对 的调用malloc()memset()包装调用,以强制提交页面。 这有助于确保如果分配导致应用程序超出其 RAM 限制,OS 将立即且可预测地终止它。 等待访问分配的页将引入延迟内存不足崩溃的风险,这更难重现和诊断。
    • 在开发模式下启用 堆内存分配跟踪
  • 避免与大字符串一起使用 Log_Debug ,并删除这些调用 (例如, #ifdef) 不在开发模式下。 Log_Debug 导致分配临时缓冲区,导致与大型字符串一起使用时 RAM 使用率突然突发。
  • 尽可能对定期异步任务使用 EventLoop API, (例如) 与外围设备交互,而不是创建线程。 创建线程会导致 Linux 内核分配额外的内存,这些内存归于应用程序。 这会降低应用的确定性,因为它会增加 OS 计划程序在可能导致应用程序超出其 RAM 限制的多个不同操作之间切换的概率。 许多 Azure Sphere 示例应用程序(如 GPIO_HighLevelApp)演示了如何使用 EventLoop。
  • 避免过早使用内存缓存来获取可在运行时重新计算的值。
  • 使用 libcurl 时:
    • 使用 libcurl 时优化最大套接字缓冲区大小。 Azure Sphere OS 将分配归因于应用程序的 RAM 使用情况的套接字缓冲区。 减少这些缓冲区大小是减少应用程序的 RAM 占用量的好方法。 请注意,使套接字缓冲区过小将对 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_BUFFERSIZECURLOPT_UPLOAD_BUFFERSIZE 参数。

      • Libcurl 还支持通过使用 curl_global_init_mem 和传入 、、freereallocstrdupcallocmalloc回调函数来重写其内部内存函数。 此功能使你能够跟踪动态分配,甚至更改行为。 例如,可以预先分配内存池,然后使用这些回调从该池分配 libcurl 内存。 这可以是设置防护措施和提高应用程序的确定性的有效方法。 有关如何使用这些回调的详细信息,请参阅 curl_global_init_mem libcurl 文档。

        注意

        此回调机制并不涵盖由 libcurl 引起的所有内存分配,仅涵盖由 libcurl 本身直接进行的内存分配。 具体而言,不会跟踪由 wolfSSL 在下方进行的分配。