上位レベルのアプリケーションでの 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 カーネルによって、アプリケーションに属性付けされた追加のメモリが割り当てられます。 これにより、アプリケーションが RAM 制限を超える可能性がある複数の個別の操作間で OS スケジューラが切り替わる確率が高まるため、アプリの決定性が低下します。 GPIO_HighLevelAppなどの Azure Sphere サンプル アプリケーションの多くは、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_BUFFERSIZE パラメーターと CURLOPT_UPLOAD_BUFFERSIZE パラメーターも同様に調整できます。

      • Libcurl では、および のコールバック関数を使用してcurl_global_init_mem渡すことによって、内部メモリ関数mallocreallocfreestrdupのオーバーライドもサポートされています。calloc この機能を使用すると、動的割り当てを追跡したり、動作を変更したりできます。 たとえば、メモリ プールを事前に割り当ててから、これらのコールバックを使用してそのプールから libcurl メモリを割り当てることができます。 これは、ガードレールを設定し、アプリケーションの決定性を高めるための効果的な手法です。 これらのコールバックの使用方法の詳細については、 curl_global_init_mem libcurl のドキュメントを参照してください。

        メモ

        このコールバック メカニズムは、libcurl によって引き起こされるすべてのメモリ割り当てをカバーするわけではありません。libcurl 自体によって直接行われたメモリ割り当てのみが対象となります。 具体的には、下の wolfSSL によって行われた割り当ては追跡されません。