Wie kann die Menge des zugewiesenen Speichers unter Linux (und OSX) abgefragt werden?

8

Obwohl das wie ein Duplikat aus anderen Fragen aussieht, lassen Sie mich erklären, warum das nicht so ist.

Ich suche nach einem bestimmten Teil meiner Anwendung, um bei Erreichen eines bestimmten Speicherlimits ordnungsgemäß abgebaut zu werden. Ich hätte Kriterien verwenden können, die auf dem verbleibenden verfügbaren physischen Speicher basieren, aber dies wäre nicht sicher, da das Betriebssystem den von meiner Anwendung verwendeten Speicher auslagern könnte, bevor die Kriterien erfüllt sind, die glauben, dass noch physischer Speicher vorhanden ist Zuweisen usw. Aus dem gleichen Grund kann ich nicht die Menge an aktuellem Speicher verwenden, die momentan vom Prozess verwendet wird, denn sobald das Betriebssystem mich ausschaltet, würde ich weiterhin den Speicher der OS-Seiten zuweisen, so dass die Nummer würde nicht mehr wachsen.

Aus diesem Grund wählte ich ein Kriterium basierend auf der Menge an Speicher, die von meiner Anwendung zugewiesen wurde, d. h. sehr nah an der Größe des virtuellen Speichers.

Diese Frage ( Wie CPU zu bestimmen und Speicherverbrauch von innerhalb eines Prozesses? ) bietet große Möglichkeiten, die Menge an virtuellem Speicher abzufragen, die von dem aktuellen Prozess verwendet wird, was ich dachte, was ich brauchte.

Unter Windows verwende ich GetProcessMemoryInfo() und das PrivateUsage -Feld, was sehr gut funktioniert.

Unter Linux habe ich verschiedene Dinge ausprobiert (siehe unten), die nicht funktionierten. Der Grund, warum die Verwendung des virtuellen Speichers bei mir nicht funktioniert, liegt an etwas, das bei der Erstellung von OpenCL-Kontexten auf NVidia-Hardware unter Linux passiert. Der Treiber reserviert einen Bereich des virtuellen Speicherplatzes, der groß genug ist, um den gesamten RAM, den gesamten Tauschspeicher und den gesamten Videospeicher aufzunehmen. Meine Vermutung ist, dass es für einheitlichen Adressraum und alles tut. Es bedeutet aber auch, dass der Prozess enorme Speichermengen meldet. Auf meinem System zum Beispiel meldet top in der VIRT-Spalte 23,3 GB (12 GB RAM, 6 GB Austausch, 2 GB Videospeicher, wodurch 20 GB vom NVidia-Treiber reserviert werden).

Auf OSX, mit task_info() und dem virtual_size -Feld, erhalte ich auch eine größere Anzahl als erwartet (ein paar GB für eine App, die unter Windows nicht einmal 1 GB erreicht), aber nicht so groß wie Linux.

Hier ist also die große Frage: Wie bekomme ich den von meiner Anwendung zugewiesenen Speicher? Ich weiß, dass dies eine etwas vage Frage ist (was bedeutet "zugewiesene Erinnerung"?), Aber ich bin flexibel:

  • Ich würde es vorziehen, die Anwendung statische Daten, Code-Abschnitt und alles, aber ich kann ohne leben.
  • Ich würde es vorziehen, den Speicher für Stacks zu verwenden, aber ich kann ohne leben.
  • Ich würde es vorziehen, den von Shared Libraries verwendeten Speicher zu verwenden, aber ich kann ohne leben.
  • Ich interessiere mich nicht wirklich für mmap Zeug, ich kann mit oder ohne an diesem Punkt tun.
  • usw.

Was wirklich wichtig ist, ist, dass die Zahl mit der dynamischen Zuweisung wächst (neu, malloc, alles) und schrumpft, wenn der Speicher freigegeben wird (von dem ich weiß, dass er implementierungsabhängig sein kann).

Dinge, die ich versucht habe

Hier sind ein paar Lösungen, an denen ich versucht habe und / oder gedacht habe, aber das würde für mich nicht funktionieren.

  1. Lesen von / proc / self / status

    Dies ist der Ansatz, der vorgeschlagen wird, wie CPU-und-Speicher-Verbrauch-von-innerhalb-eines-Prozesses zu bestimmen ist. Wie oben erwähnt, gibt dies jedoch die Menge an virtuellem Speicher zurück, die für mich nicht funktioniert.

  2. Lesen von / proc / self / statm

    Sehr leicht am schlechtesten: nach Ссылка , die sich auf Linux-Kernel-Code bezieht, der einzige Unterschied zwischen diesen beiden Werten besteht darin, dass der zweite Wert reserved_vm nicht auf die Menge des virtuellen Speichers subtrahiert. Ich hätte gehofft, dass reserved_vm den vom OpenCL-Treiber reservierten Speicher enthalten würde, aber nicht.

  3. Verwenden Sie mallinfo() und das Feld uordblks

    Dies scheint nicht alle Zuordnungen zu enthalten (ich vermute die new s fehlen), da für einen + 2Gb Wachstum im virtuellen Speicherraum (nach einigen speicherintensiven Arbeiten und immer noch den Speicher halten) , Ich sehe nur etwa 0,1 GB Wachstum in der Anzahl von mallinfo() zurückgegeben.

  4. Lesen Sie die Größe des Abschnitts [heap] aus / proc / self / smaps

    Dieser Wert begann bei etwa 336.760 Kb und erreichte bei 1.019.496 Kb einen Spitzenwert für Arbeit, bei der der virtuelle Speicher um +2 Gb anwuchs, und dann geht es nie runter, also bin ich mir nicht sicher, ob ich mich wirklich auf diese Zahl verlassen kann. .

  5. Überwachen Sie alle Speicherzuweisungen in meiner Anwendung

    Ja, in einer idealen Welt hätte ich die Kontrolle über jeden, der Speicher zuweist. Dies ist jedoch eine Legacy-Anwendung, die viele verschiedene Allokatoren verwendet, einige malloc s, einige new s, einige betriebssystemspezifische Routinen usw.Es gibt einige Plug-Ins, die tun können, was immer sie wollen, sie könnten mit einem anderen Compiler kompiliert werden, usw. Während dies großartig wäre, um den Speicher wirklich zu kontrollieren, funktioniert das in meinem Kontext nicht.

  6. Lesen Sie die Größe des virtuellen Speichers vor und nach der OpenCL-Kontextinitialisierung

    Während dies ein "hacky" Weg sein könnte, um das Problem zu lösen (und ich könnte darauf zurückfallen), würde ich wirklich wünschen eine zuverlässigere Möglichkeit, Speicher abzufragen, weil OpenCL-Kontext könnte irgendwo aus meinem initialisiert werden Kontrolle, und andere ähnliche, aber nicht OpenCL-spezifische Probleme könnten sich einschleichen und ich würde nichts davon wissen.

Das ist also alles, was ich habe. Es gibt noch eine Sache, die ich noch nicht ausprobiert habe, weil sie nur auf OSX funktioniert, aber es ist die Methode, die in Warum zeigen mstats und malloc_zone_statistics nach dem freien Speicher keinen wiederhergestellten Speicher? , dh benutzen Sie malloc_get_all_zones() und malloc_zone_statistics() , aber ich denke, dies könnte das gleiche Problem wie mallinfo() sein, dh nicht alle Zuordnungen berücksichtigen.

Kann jemand also einen Weg vorschlagen, um die Speichernutzung eines bestimmten Prozesses unter Linux (und auch OSX, selbst wenn es eine andere Methode ist) abzufragen (so vage ein solcher Begriff, siehe oben für Präzision)?

>     
Martin Bisson 20.07.2016, 20:32
quelle

3 Antworten

0

Hier ist, was ich am Ende benutzt habe. Ich scanne / proc / self / maps und summiere die Größe aller Adressbereiche, die meinen Kriterien entsprechen, nämlich:

  • Nur Bereiche von Inode 0 einbeziehen (d. h. keine Geräte, keine zugeordnete Datei usw.)
  • Nur Bereiche einschließen, die lesbar, beschreibbar oder ausführbar sind
  • Nur privaten Speicher einschließen
    • In meinen Experimenten habe ich keine Instanzen von shared memory von inode 0 gesehen. Vielleicht mit interprozess-shared memory ...?

Hier ist der Code für meine Lösung:

%Vor%

Da dies Schleife durch alle Zeilen in / proc / self / Karten, Speicher Abfrage auf diese Weise wesentlich langsamer ist als die Verwendung von „Virtual Memory derzeit aktuellen Prozess verwendet“ von Wie aus dem Innern einer Prozess-CPU und Speicherverbrauch bestimmen? .

Es liefert jedoch eine Antwort viel näher an das, was ich brauche.

    
Martin Bisson 30.03.2017, 19:19
quelle
1

Sie können versuchen, Informationen zu verwenden, die von getrusage() :

zurückgegeben wurden %Vor%

Wenn die Speicherinformation passt nicht Sie dazu die Seitenfehler zählt die Beobachtung kann Monitor Speicher Stress helfen, das ist, was Sie erkennen möchten.

    
chqrlie 20.07.2016 20:46
quelle
1

Haben Sie versucht, einen Shared Library Interposer für Linux für Abschnitt (5) oben? Solange Ihre Anwendung ist nicht statisch, die malloc Funktionen verknüpfen, können Sie eine neue Funktion zwischen Ihrem Programm und dem Kernel malloc dazwischenstellen. Ich habe diese Taktik viele Male benutzt, um Statistiken über die Speichernutzung zu sammeln.

Es muss LD_PRELOAD gesetzt werden, bevor das Programm ausgeführt wird, aber keine Quell- oder Binäränderungen. Es ist eine ideale Antwort in vielen Fällen.

Hier ist ein Beispiel für einen malloc Interposer:

Ссылка

Sie werden wahrscheinlich auch Calloc und Free machen wollen. Anrufe auf neue Anrufe enden im Allgemeinen als Anruf bei malloc, so dass auch C ++ abgedeckt wird.

OS X scheint ähnliche Fähigkeiten zu haben, aber ich habe es nicht ausprobiert.

Ссылка

- Matt

    
Matthew Fisher 24.07.2016 00:26
quelle

Tags und Links