Frage

Ich arbeite auf einem Embedded-Prozessor (400 MHz Intel PXA255 XScale), und ich dachte, dass ich einen Fall gesehen, wo es nicht genügend Speicher war einen ‚neuer‘ Betrieb gerecht zu werden. Das Programm nicht abstürzen, so nahm ich an andere Threads ihr Gedächtnis befreit hatte und es war nur eine vorübergehende Sache. Dies ist ein paar ziemlich kritischer Code, so verläßt, ist keine Option, und eine Art von Fehler muss die Remote-Benutzer zurückgegeben werden.

Würde die folgenden kleinen fix genug sein, um das Problem zu lösen, oder gibt es einen besseren Weg? Vor dem Austausch jeden ‚neuen‘ mit dem folgenden Code, dachte ich, ich würde fragen.

char someArr[];
do{ 
    someArr = new char[10]; 
    Sleep(100); // no justification for choosing 100 ms
} while ( someArr == NULL );

Ist die Sleep-Hilfe? Soll ich eine maximale Anzahl von Wiederholungen? Ist es möglich, überall statische Initialisierung zu benutzen?

FINAL UPDATE: Vielen Dank für die hilfreichen Antworten sehr viel, aber es stellt sich heraus, ein Fehler für fehlerhafte Speicherzuweisung im Code war zu prüfen. Ich werde alle diese Antworten im Auge behalten, und so viele malloc die neuen und die ersetzen, wie ich kann, wenn auch (vor allem im Fehlerbehandlungscode).

War es hilfreich?

Lösung

Es gibt ein paar verschiedene Möglichkeiten, dies zu attackieren - beachten Sie, dass die Werkzeug Anweisungen ein wenig variieren, basierend auf welcher Version von Windows CE / Windows Mobile Sie verwenden.

Einige Fragen zu beantworten:

1. Ist Ihr Anwendungsspeicher undicht ist, auf diese Bedingung für wenig Arbeitsspeicher führt?

2. Ist Ihre Anwendung einfach zu viel Speicher in bestimmten Phasen verwenden, was zu diesem niedrigen Speicherzustand?

1 und 2 kann mit dem Windows CE AppVerifier Tool untersucht werden, die detaillierten Speicher Logging-Tools für Ihr Produkt anbieten kann. Andere Haufen Verpackungs Tools können auch ähnliche Informationen zur Verfügung stellen (und können mit höherer Leistung sein), je nach Produkt-Design.

http://msdn.microsoft.com/en-us/library /aa446904.aspx

3. Sind Sie Aufteilung und sehr häufig in diesem Prozess Arbeitsspeicher freigegeben werden?

Windows CE vor OS Version 6.0 (nicht zu verwechseln mit Windows Mobile 6.x) hatte einen 32MB / Prozess Limit des virtuellen Speichers, die viel Spaß Fragmentierungsprobleme zu verursachen neigt. In diesem Fall, auch wenn Sie ausreichend physische Speicher frei haben, können Sie aus virtuellem Speicher ausgeführt werden. Verwendung von benutzerdefinierten Blockverteilern ist in der Regel eine Milderung für dieses Problem.

4. Sind die Zuweisung Sie sehr große Speicherblöcke? (> 2 MB)

bis 3 Verwandte, könnten Sie einfach den Prozessraum des virtuellen Speichers anstrengend werden. Es gibt Tricks, etwas abhängig von OS-Version, Speicher in einem gemeinsam genutzten virtuellen Speicher zuweisen, außerhalb des Prozessraums. Wenn Sie aus der VM ausgeführt wird, aber nicht physischen RAM, könnte dies helfen.

5. Sind Sie mit einer großen Anzahl von DLLs?

Auch in Bezug auf 3, je nach OS-Version, DLLs auch sehr schnell gesamte verfügbare VM reduzieren.

Weitere Abspringen Punkte:

Übersicht über die CE-Memory-Tools

http://blogs.msdn.com/ce_base /archive/2006/01/11/511883.aspx

Zielsteuerungsfenster 'mi' Werkzeug

http://msdn.microsoft.com/en-us/library /aa450013.aspx

Andere Tipps

Sie versuchen, ein globales Problem durch lokale Argumentation zu lösen. Das globale Problem ist, dass die gesamte Vorrichtung eine begrenzte Menge an RAM hat (und möglicherweise Zusatzspeicher) für das Betriebssystem und alle Anwendungen. Um sicherzustellen, dass diese Menge an RAM nicht überschritten wird, haben Sie ein paar Optionen:

  • Jeder Prozess arbeitet in einer festen Menge an RAM pro Prozess zu Startzeit bestimmt werden; Der Programmierer hat die Argumentation, dass alles passt zu machen. Also, Ja, ist es möglich, alles zu vergeben statisch . Es ist nur eine Menge Arbeit, und jedes Mal, wenn Sie die Konfiguration Ihres Systems ändern, müssen Sie die Zuordnungen überdenken .

  • Prozesse sind sich ihrer eigenen Speichernutzung und die Bedürfnisse und beraten ständig einander über, wie viel Speicher sie benötigen. Sie wirken zusammen, so dass sie nicht über genügend Arbeitsspeicher ausgeführt . Dies setzt voraus, dass zumindest einige Prozesse im System können ihre eigenen Speicheranforderungen anzupassen (beispielsweise durch die Größe eines internen Cache ändern). Alonso und Appel ein Papier über diesen Ansatz geschrieben.

  • Jeder Prozess ist sich bewusst, dass der Speicher erschöpft und kann ein Failover auf einen Zustand, in dem es eine minimale Menge an Speicher verbraucht . Oft wird diese Strategie durch, die eine out-of-memory Ausnahme umgesetzt. Die Ausnahme ist in oder in der Nähe von main () und das out-of-Speicher gehandhabt Ereignis startet das Programm im wesentlichen bei Null. Dieser Failover-Modus arbeiten kann, wenn der Speicher in Reaktion auf Benutzeranforderungen wächst; wenn die Speicher der Programmanforderung wächst unabhängig von dem, was der Benutzer tut, kann es zu Dreschen führen.

Ihr Vorschlag oben passt keines der Szenarien. Stattdessen Sie hoffen, ein anderer Prozess das Problem lösen und die Speicher Sie müssen schließlich erscheinen. Vielleicht haben Sie Glück. Das könnte dir nicht.

Wenn Sie Ihr System wollen zuverlässig arbeiten zu können, würde gut daran tun, überdenken das Design jeden Prozess auf dem System ausgeführt in Anbetracht der Notwendigkeit, begrenzten Speicher zu teilen. Es könnte eine größere Aufgabe, als Sie erwartet, aber wenn Sie das Problem zu verstehen, können Sie dies tun. Viel Glück!

Es gibt viele gute Dinge in den anderen Antworten, aber ich es dachte hinzuzufügen, dass, wenn alle Fäden in einer ähnlichen Schleife erhalten, dann wird das Programm blockiert werden.

Die „richtige“ Antwort auf diese Situation ist wahrscheinlich strenge Grenzen für die verschiedenen Teile des Programms zu haben, um sicherzustellen, dass sie nicht über Speicher verbrauchen. Das würde wahrscheinlich große Abschnitte in allen Teilen des Programms erfordert neu zu schreiben.

Die zweitbeste Lösung wäre, eine Callback haben, wo ein gescheiterter Zuordnungsversuch den Rest des Programms sagen kann, die mehr Speicher benötigt wird. Vielleicht sind andere Teile des Programms können einige Puffer freigeben aggressiver, als sie normalerweise, oder Speicher-Cache-Suchergebnisse verwendet loslassen, oder so etwas. Dies würde neuen Code für andere Teile des Programms benötigen. Dies ist jedoch schrittweise getan werden könnte, anstatt eine Rewrite über das gesamte Programm erforderlich ist.

wäre eine andere Lösung zu haben sein das Programm schützen groß (temporär) Speicheranforderungen mit einem Mutex. Es klingt wie Sie sicher sind, dass der Speicher bald freigegeben werden, wenn Sie nur es später noch einmal versuchen. Ich schlage vor, dass Sie einen Mutex für Operationen verwenden, die viel Speicher verbrauchen könnte, wird dies der Faden erlauben sofort aufgeweckt werden, wenn ein anderer Thread den Speicher freigegeben hat, die benötigt wird. Andernfalls wird Ihr Gewinde selbst für ein Zehntel einer Sekunde schlafen, wenn der Speicher sofort freigibt.

Sie können auch schlafen (0) versuchen, die einfach die Kontrolle einen anderen Thread Hand von wird, der bereit ist zu laufen. Auf diese Weise können Sie Ihre Thread-Steuerung sofort wieder, wenn alle anderen Threads schlafen gehen, anstatt seine 100-Millisekunden-Satz zu warten. Aber wenn mindestens ein Thread noch laufen will, werden Sie noch warten müssen, bis sie die Kontrolle aufgibt. Dies ist in der Regel 10 Millisekunden auf Linux-Rechnern, zuletzt geprüft ich. Ich weiß nicht, über andere Plattformen. Ihr Gewinde kann auch eine niedrigere Priorität im Scheduler hat, wenn sie freiwillig zu schlafen gegangen sind.

Auf der Grundlage Ihrer Frage, ich gehe davon aus, dass Ihr Haufen von mehreren Threads gemeinsam genutzt wird.

Wenn es nicht dann über dem Code wird nicht funktionieren, weil nichts von dem Haufen befreit werden, während die Schleife ausgeführt wird.

Wenn der Haufen geteilt wird, dann würde die oben wahrscheinlich funktionieren. wenn Sie einen gemeinsam genutzten Heap jedoch haben, rufen dann „neu“ wird wahrscheinlich dazu führen, entweder ein Spin-Lock (eine ähnliche Schleife die, die Sie haben, aber unter Verwendung von CAS Anweisungen), oder es wird auf der Grundlage einiger Kernel-Ressourcen blockieren.

In beiden Fällen wird die Schleife Sie haben den Durchsatz des Systems verringern. Dies liegt daran, Sie werden entweder mehr Kontext entstehen schaltet dann auf die Sie benötigen, oder länger dauern, bis der reagieren „Speicher ist ab sofort verfügbar“ Ereignis.

Ich würde die „neuen“ und „Löschen“ Betreiber überschreiben. Wenn neue ausfällt können Sie blockieren (oder Spin-Sperre auf eine Zählvariable irgendeiner Art) für einen anderen Thread auf freien Speicher warten, und dann können gelöscht werden entweder die blockierte „neue“ Fadensignal oder die Zählervariable mit CAS erhöhen.

Das sollte man einen besseren Durchsatz geben und ein bisschen mehr efficent sein

Ein paar Punkte:

  • Embedded Programme zuweisen oft den gesamten Speicher beim Start oder verwenden Sie nur statische Speicher Situationen wie diese zu vermeiden.
  • Es sei denn, es ist etwas anderes auf dem Gerät ausgeführt wird, der Speicher auf einer regelmäßigen Basis befreit Ihre Lösung nicht geeignet, um wirksam zu sein.
  • Die Viper I hat 64MB RAM haben, ich glaube nicht, dass sie mit weniger als 32 MB kommen, wie viel Speicher Ihre Anwendung mit?

ich zweitens, dass das Vernünftigste, was zu tun ist, statische Zuweisung von Speicher zu verwenden, so dass Sie eine Vorstellung davon haben, was los ist. Dynamische Speicherzuweisung ist eine schlechte Angewohnheit von Desktop-Programmierung, die nicht auf eingeschränkte Ressource Maschinen geeignet ist (es sei denn, Sie ein gutes Stück Zeit und Mühe, um ein gutes verwalten die Erstellung und Speicher-Management-Systems gesteuert).

Überprüfen Sie auch, was das Betriebssystem auf Ihrem Gerät verfügt (vorausgesetzt, es ein High-End-ARM-Geräte hat wie dieses ein Betriebssystem zu laufen neigt) hat für Speicherverwaltung.

Sie verwenden C ++. So können Sie die Verwendung einiger C ++ Dienstprogramme machen Ihnen das Leben leichter zu machen. Zum Beispiel, warum verwendet new_handler nicht?

void my_new_handler() {
    // make room for memory, then return, or throw bad_alloc if
    // nothing can be freed.
}

int main() {
    std::set_new_handler(&my_new_handler);

    // every allocation done will ask my_new_handler if there is
    // no memory for use anymore. This answer tells you what the
    // standard allocator function does: 
    // https://stackoverflow.com/questions/377178
}

In den new_handler, könnten Sie alle Anwendungen, die ein Signal senden, so dass sie wissen, dass Speicher für eine Anwendung benötigt wird, und dann noch ein bisschen warten andere Anwendungen, die Zeit zu geben, den Antrag auf Speicher zu erfüllen. Wichtig ist, dass Sie auf etwas tun und nicht leise Hoffnung für den verfügbaren Speicher. Der neue Betreiber wird Ihre Handler wieder aufrufen, wenn noch nicht genügend Speicher vorhanden ist, so dass Sie sich nicht darum kümmern, ob alle Anwendungen, die bereits den benötigten Speicher free'ed haben. Sie können auch Überlastung Operator neuer , wenn Sie die Größe des Speichers wissen müssen, die in dem new_handler benötigt wird. Sehen Sie mein andere Antwort , wie das zu tun. Auf diese Weise haben Sie einem zentralen Ort Speicherprobleme zu behandeln, statt viele Orte mit dem betroffenen.

Wie andere erwähnt haben, im Idealfall würden Sie dieses Problem vermeiden, indem Sie up-Front-Design und Software-Architektur, aber ich bin an diesem Punkt unter der Annahme, dass wirklich keine Option ist.

Als ein andere Stelle erwähnt, wäre es gut, die Logik in einigen Utility-Funktionen zu wickeln, so dass Sie nicht über den Out-of-Memory-Code zu schreiben am Ende alle von der Stelle.

, um das eigentliche Problem zu erhalten, versuchen Sie eine gemeinsam genutzte Ressource, Speicher zu verwenden, aber sie sind nicht in der Lage, weil das gemeinsam genutzte Ressource wird von einem anderen Thread in dem System verwendet wird. Im Idealfall ist für einen warten, was Sie tun mögen der anderen Threads in dem System die Ressource, die Sie benötigen, zu lösen, und dann diese Ressource erwerben. Wenn Sie eine Möglichkeit hatten alle die Zuteilung des Abfangens und kostenlose Anrufe können Sie Set-up etwas, so dass der Zuweisungsfaden, bis der Speicher blockiert war vorhanden, und die Freigabe signalisiert die Zuweisung von Thread, wenn Speicher zur Verfügung steht. Aber ich gehe davon aus, dass ist einfach zu viel Arbeit.

In Anbetracht der Einschränkungen nicht in der Lage, völlig neu Architekt das System oder die Speicherzuordner neu zu schreiben, dann denke ich, Ihre Lösung die praktischste ist, so lange wie Sie (und die anderen in Ihrem Team), verstehen die Grenzen, und die Probleme, es wird die Spur führt nach unten.

Jetzt Ihren spezifischen Ansatz zu verbessern, können Sie die Auslastungen zu messen, um zu sehen, wie oft Speicher zugewiesen werden und befreit. Dies würde Ihnen eine bessere ay der Berechnung, was das Wiederholungsintervall sein sollte.

Zweitens wollen Sie Art und Weise versuchen, für jede Iteration des Timeout-Erhöhung der Last des Threads auf dem System zu reduzieren.

Schließlich sollten Sie auf jeden Fall einige Zeit der Fehler / Panikfall, wenn der Thread nicht in der Lage ist ein Fortschritt nach einer Anzahl von Iterationen zu machen. So können Sie zumindest das Potenzial Live-Lock-Fall sehen, die auftreten können, wenn alle Fäden für einen anderen Thread in dem System freien Speicher warten. Sie könnten einfach eine Anzahl von Iterationen holen auf, was empirisch Arbeit gezeigt wird, oder man könnte darüber erhalten intelligente und zu verfolgen, wie viele Threads für Speicher stecken warten, und wenn diese Panik zu sein alle Fäden endet.

Hinweis : Das ist natürlich keine perfekte Lösung, und wie die anderen Plakate eine globalere Sicht der Anmeldung erwähnt als Ganzes benötigt wird, um das Problem richtig zu lösen, aber die oben ist ein praktisches Technik, die in den kurzfristigen.

funktionieren sollte

Sicher würde es davon ab, ob Sie eine vernünftige Erwartung Speicher haben in den 100 verfügbar wird (Millisekunden?) Schlafen? Sicherlich sollten Sie die Anzahl der begrenzen versucht es.

Für mich etwas nicht hier riechen. Hmmm ...

Eingebettete Systeme müssen in der Regel extrem deterministisch sein - vielleicht sollten Sie das gesamte System und Leiter des Potenzials für diese Bewertung vorne zum Scheitern verurteilt; und dann einfach nicht schwer, es geschieht es tatsächlich in der Praxis.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top