Teilen über


Bewährte Methoden zum Verwalten der RAM-Verwendung in high-level-Anwendungen

Wichtig

Dies ist die Dokumentation zu Azure Sphere (Legacy). Azure Sphere (Legacy) wird am 27. September 2027 eingestellt, und Benutzer müssen bis zu diesem Zeitpunkt zu Azure Sphere (integriert) migrieren. Verwenden Sie die Versionsauswahl oberhalb des Inhaltsverzeichniss, um die Dokumentation zu Azure Sphere (Integriert) anzuzeigen.

Obwohl das Azure Sphere-Betriebssystem den Linux-Kernel als Basis verwendet, ist es wichtig zu beachten, dass Sie weiterhin Anwendungen für ein eingebettetes Gerät mit erheblichen RAM-Einschränkungen schreiben. Durch die Anwendung guter eingebetteter Programmierpraktiken können Sie zuverlässige Azure Sphere-Anwendungen erstellen.

Wichtig

Um genaue RAM-Verwendungsinformationen für Ihre Anwendung zu erhalten, ist es wichtig, dass Sie Ihre App ohne Debugging ausführen. Das Ausführen Ihrer App unter dem Debugger führt zu einer überhöhten RAM-Nutzung, da ram, der vom Debugserver verbraucht wird, in die gemeldeten RAM-Nutzungsstatistiken einbezogen werden. Weitere Informationen zu Speicherstatistiken für anwendungen, die auf dem angeschlossenen Gerät ausgeführt werden, finden Sie unter "Arbeitsspeichernutzung" in Anwendungen auf hoher Ebene.

Im Folgenden sind einige bewährte Methoden aufgeführt:

  • Weisen Sie Vorabspeicher (idealerweise statisch) zu, und lassen Sie sie nach Möglichkeit für die Lebensdauer Der Anwendung zugewiesen. Dadurch wird die Determinität der RAM-Nutzung Ihrer Anwendung erheblich erhöht und das Risiko des Speicherbedarfs erhöht und die Fragmentierung über die Lebensdauer Ihrer Anwendung verringert.
  • Wenn die dynamische Zuordnung unbedingt erforderlich ist:
    • Versuchen Sie, die Häufigkeit der Heap-Speicherzuweisungen und Deallocations zu minimieren, die von der Anwendung durchgeführt werden, um Risiken der Heap-Speicherfragmentierung zu reduzieren, z. B. durch Nutzung von Techniken für die Blockzuordnung/Speicherpool.
    • Überprüfen Sie Stapelseiten und schließen Sie aufrufe malloc() nach Möglichkeit mit Aufrufen um, um das Commit von Seiten zu memset() erzwingen. Dadurch wird sichergestellt, dass das Betriebssystem sofort und vorhersagbar beendet wird, wenn eine Zuordnung dazu führt, dass die Anwendung ihren RAM-Grenzwert überschreitet. Das Warten auf den Zugriff auf zugewiesene Seiten führt zu einem verzögerten Absturz außerhalb des Arbeitsspeichers, der schwieriger zu reproduzieren und diagnostizieren ist.
    • Aktivieren Sie die Speicherzuordnungsnachverfolgung im Entwicklungsmodus.
  • Vermeiden Sie die Verwendung Log_Debug mit großen Zeichenfolgen, und entfernen Sie diese Aufrufe (z. B. bei einem #ifdef) nicht im Entwicklungsmodus. Log_Debug bewirkt, dass temporäre Puffer zugewiesen werden, was zu plötzlichen Brüchen bei der RAM-Verwendung führt, wenn sie mit großen Zeichenfolgen verwendet werden.
  • Verwenden Sie die EventLoop-API nach Möglichkeit für regelmäßige asynchrone Aufgaben (z. B. interaktion mit Peripheriegeräten), anstatt Threads zu erstellen. Durch das Erstellen von Threads wird der Linux-Kernel zusätzlichem Arbeitsspeicher zugewiesen, der Ihrer Anwendung zugeordnet ist. Dadurch wird der Determinismus Ihrer App reduziert, da die Wahrscheinlichkeit des Wechsels des Betriebssystemplanrs zwischen mehreren, unterschiedlichen Vorgängen erhöht wird, die dazu führen können, dass die Anwendung ihren RAM-Grenzwert überschreitet. Viele der Azure Sphere-Beispielanwendungen, z. B. die GPIO_HighLevelApp, veranschaulichen die Verwendung von EventLoop.
  • Vermeiden Sie vorzeitige Verwendung von Speichercaches für Werte, die zur Laufzeit neu kompiliert werden können.
  • Bei Verwendung von libcurl:
    • Optimieren Sie die maximalen Socketpuffergrößen bei Verwendung von libcurl. Azure Sphere OS weist Socketpuffer zu, die der RAM-Verwendung Ihrer Anwendung zugeordnet sind. Das Verringern dieser Puffergrößen kann eine gute Möglichkeit sein, den RAM-Speicherbedarf Ihrer Anwendung zu reduzieren. Beachten Sie, dass das Erstellen zu kleiner Socketpuffer die Leistung von libcurl beeinträchtigt. Optimieren Sie stattdessen die maximalen Puffergrößen für Ihr Szenario:

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

      Weitere Informationen finden Sie in der CURLOPT_SOCKOPTFUNCTION libcurl-Dokumentation.

      • Die CURLOPT_BUFFERSIZE- und CURLOPT_UPLOAD_BUFFERSIZE parameter auf höherer Ebene können auf ähnliche Weise abgestimmt werden.

      • Libcurl unterstützt auch das Überschreiben der internen Speicherfunktionen mithilfe curl_global_init_mem und Übergeben von Rückruffunktionen für malloc, , free, realloc, strdupund calloc. Mit dieser Funktion können Sie dynamische Zuordnungen nachverfolgen oder sogar das Verhalten ändern. Sie können beispielsweise vorab einen Speicherpool zuweisen und dann diese Rückrufe verwenden, um libcurl-Speicher aus diesem Pool zuzuweisen. Dies kann eine effektive Technik für das Setzen von Schutzläufen und die zunehmende Determinismus Ihrer Anwendung sein. Weitere Informationen zur Verwendung dieser Rückrufe finden Sie in der curl_global_init_mem libcurl-Dokumentation.

        Hinweis

        Dieser Rückrufmechanismus deckt nicht alle Speicherzuweisungen ab, die durch libcurl verursacht werden, nur diejenigen, die direkt von libcurl selbst vorgenommen wurden. Insbesondere werden zuordnungen von wolfSSL darunter nicht nachverfolgt.