高度なアプリケーションでの RAM 使用率を管理するためのベスト プラクティス
重要
これは Azure Sphere (レガシ) のドキュメントです。 Azure Sphere (レガシ) は 2027 年 9 月 27 日に 再提供されておりユーザーは現時点で Azure Sphere (統合) に移行する必要があります。 TOC の上にある Version セレクターを使用して、Azure Sphere (統合) のドキュメントを表示します。
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
を使用して内部メモリ関数をオーバーライドし、malloc
、free
、realloc
、strdup
、およびcalloc
のコールバック関数を渡すこともできます。 この機能を使用すると、動的割り当てを追跡したり、動作を変更したりできます。 たとえば、メモリプールを事前に割り当ててから、これらのコールバックを使用してそのプールから libcurl メモリを割り当てることができます。 これは、ガードレールを設定し、アプリケーションの決定性を高めるための効果的な手法です。 これらのコールバックの使用方法の詳細については、 curl_global_init_mem libcurl のドキュメントを参照してください。Note
このコールバック メカニズムでは、libcurl によって引き起こされるすべてのメモリ割り当てには対応せず、libcurl 自体によって直接行われたメモリ割り当てのみが対象となります。 具体的には、wolfSSL によって下に行われた割り当ては追跡されません。