2016-07-20 9 views
8

Während dies wie ein Duplikat aus anderen Fragen aussehen könnte, lassen Sie mich erklären, warum es nicht ist.Wie kann die Menge des zugewiesenen Speichers unter Linux (und OSX) abgefragt werden?

Ich suche, um einen bestimmten Teil meiner Anwendung zu verschlechtern, wenn ein bestimmtes Speicherlimit erreicht wurde. 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 von meiner Anwendung zugewiesen, d. H. Sehr nahe an virtuellen Speichergröße.

Diese Frage (How to determine CPU and memory consumption from inside a process?) bietet großartige Möglichkeiten, die Menge an virtuellem Speicher abzufragen, die vom aktuellen Prozess verwendet wird, was ich dachte, was ich brauchte. In Windows verwende ich GetProcessMemoryInfo() und das PrivateUsage Feld, das funktioniert gut

Unter Linux habe ich mehrere Dinge ausprobiert (unten aufgeführt), 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. Das bedeutet aber auch, dass der Prozess große Speichermengen meldet. Auf meinem System zum Beispiel top melden 23,3 GB in der VIRT-Spalte (12 GB RAM, 6 GB Wechsel, 2 GB Videospeicher, die 20 GB durch den NVidia-Treiber reserviert).

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

Also hier ist die große Frage: Wie bekomme ich die Menge an Speicher von meiner Anwendung zugewiesen? Ich weiß, dass dies eine etwas vage Frage ist (was bedeutet „zugewiesenen Speicher“ bedeutet?), Aber ich bin flexibel:

  • Ich würde es vorziehen, die Anwendung von statischen Daten, Codeabschnitt und alles umfassen, aber ich kann Leben ohne.
  • Ich würde es vorziehen, den Speicher für Stacks zugeordnet, aber ich kann ohne leben.
  • Ich würde es vorziehen, den Speicher von gemeinsam genutzten Bibliotheken enthalten, aber ich kann ohne leben.
  • Ich interessiere mich nicht wirklich für mmap Zeug, ich kann mit oder ohne an diesem Punkt tun.
  • Etc.

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

Dinge, die ich versucht habe

Hier sind ein paar Lösungen, die ich versucht habe und/oder Gedanken an, aber das wäre für mich nicht.

  1. Lesen von/proc/self/status

    Dies ist der Ansatz, wie bestimmen-CPU-und-Speicher-Verbrauch-von-inside-a-Prozess vorgeschlagen 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 worst: nach http://kernelnewbies.kernelnewbies.narkive.com/iG9xCmwB/proc-pid-statm-doesnt-match-with-status, das Linux-Kernel-Code Bezug nimmt, ist der einzige Unterschied zwischen diesen beiden Werten, die die zweite nicht subtrahieren Sie reserved_vm auf die Menge des virtuellen Speichers. Ich hätte gehofft, dass reserved_vm den vom OpenCL-Treiber reservierten Speicher enthalten würde, aber das tut es nicht.

  3. Verwenden mallinfo() und das uordblks Feld

    Dies scheint nicht alle Zuführungen schließen (Ich vermute, die new s fehlen), da für eine + 2Gb Wachstum in einem virtuellen Speicherraum (nach einige speicherlastige Arbeit zu tun und immer noch die Erinnerung halten), sehe ich nur etwa 0,1 GB Wachstum in der Anzahl von mallinfo() zurückgegeben.

  4. Lesen Sie die [Heap] Abschnittsgröße von/proc/self/smaps

    Dieser Wert bei rund 336.760 Kb gestartet und erreichte mit 1.019.496 Kb für Arbeit, die virtuellen Speicherraum um + 2Gb wuchs, und dann es wird nie nach unten, so dass ich bin mir nicht sicher, ob ich nicht wirklich auf dieser Nummer verlassen kann ...

  5. -Monitor alle Speicherzuordnungen in meiner Anwendung

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

  6. die virtuelle Speichergröße vor und nach dem Kontext Initialisierung OpenCL Lesen

    Zwar ist dies eine „Hacky“ Art und Weise könnte das Problem (und ich könnte es Rückfall muß) zu lösen, würde ich wirklich Ich wünsche mir eine zuverlässigere Möglichkeit, Speicher abzufragen, weil der OpenCL-Kontext irgendwo außerhalb meiner Kontrolle initialisiert werden könnte und andere ähnliche, aber nicht OpenCL-spezifische Probleme auftreten könnten und ich würde nichts davon wissen.

Also das ist so ziemlich alles, was ich habe. Es gibt noch eine Sache, die ich noch nicht ausprobiert habe, denn es funktioniert nur unter OSX, aber es ist die in Why does mstats and malloc_zone_statistics not show recovered memory after free? beschriebene Methode, dh malloc_get_all_zones() und malloc_zone_statistics() zu verwenden, aber ich denke, das könnte das gleiche Problem wie mallinfo(), dh nicht sein alle Zuordnungen berücksichtigen.

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

+0

mallinfo() mit (arena + hblkhd + uordblks) –

+0

@brianbeuning: Laut http://man7.org/linux/man-pages/man3/mallinfo.3.html ist 'arena'' 'uordblks' + 'fordblks', so würde Ihr Vorschlag am Ende zweimal Speicher zählen ... –

Antwort

0

Hier ist, was ich am Ende mit. Ich scanne/proc/self/Karten und summieren die Größe der alle Adressbereiche meine Kriterien erfüllen, nämlich:

  • Nur umfassen reicht von Inode 0 (dh keine Geräte, keine mapped-Datei, etc.)
  • Nur umfassen Bereiche, die
  • nur Speicher privater mindestens einer der lesbaren, beschreibbaren oder ausführbar sind, umfassen
    • In meinen Experimenten wir nicht von Instanzen von Shared-Memory-inode sahen 0. Vielleicht mit inter-Prozess-Shared-Memory. ..?

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

size_t getValue() 
{ 
    FILE* file = fopen("/proc/self/maps", "r"); 
    if (!file) 
    { 
     assert(0); 
     return 0; 
    } 

    size_t value = 0; 

    char line[1024]; 
    while (fgets(line, 1024, file) != NULL) 
    { 
     ptrdiff_t start_address, end_address; 
     char perms[4]; 
     ptrdiff_t offset; 
     int dev_major, dev_minor; 
     unsigned long int inode; 
     const int nb_scanned = sscanf(
      line, "%16tx-%16tx %c%c%c%c %16tx %02x:%02x %lu", 
      &start_address, &end_address, 
      &perms[0], &perms[1], &perms[2], &perms[3], 
      &offset, &dev_major, &dev_minor, &inode 
      ); 
     if (10 != nb_scanned) 
     { 
      assert(0); 
      continue; 
     } 

     if ((inode == 0) && 
      (perms[0] != '-' || perms[1] != '-' || perms[2] != '-') && 
      (perms[3] == 'p')) 
     { 
      assert(dev_major == 0); 
      assert(dev_minor == 0); 
      value += (end_address - start_address); 
     } 
    } 

    fclose(file); 

    return value; 
} 

Da dies in/proc/self/Karten durch alle Linien Looping, Speicher Abfragen auf diese Weise wesentlich langsamer ist als die Verwendung von " Virtueller Speicher aktuell vom aktuellen Prozess verwendet "von How to determine CPU and memory consumption from inside a process?.

Allerdings bietet es eine Antwort viel näher, was ich brauche.

1

können Sie versuchen, und verwenden Informationen zurückgegeben von getrusage():

#include <sys/time.h> 
#include <sys/resource.h> 

int getrusage(int who, struct rusage *usage); 

struct rusage { 
    struct timeval ru_utime; /* user CPU time used */ 
    struct timeval ru_stime; /* system CPU time used */ 
    long ru_maxrss;  /* maximum resident set size */ 
    long ru_ixrss;   /* integral shared memory size */ 
    long ru_idrss;   /* integral unshared data size */ 
    long ru_isrss;   /* integral unshared stack size */ 
    long ru_minflt;  /* page reclaims (soft page faults) */ 
    long ru_majflt;  /* page faults (hard page faults) */ 
    long ru_nswap;   /* swaps */ 
    long ru_inblock;  /* block input operations */ 
    long ru_oublock;  /* block output operations */ 
    long ru_msgsnd;  /* IPC messages sent */ 
    long ru_msgrcv;  /* IPC messages received */ 
    long ru_nsignals;  /* signals received */ 
    long ru_nvcsw;   /* voluntary context switches */ 
    long ru_nivcsw;  /* involuntary context switches */ 
}; 

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

+0

Danke für den Vorschlag. Ich habe es versucht (gelesen 'ru_ixrss',' ru_idrss' und 'ru_isrss') und alle Felder haben 0.Laut der man-Seite "Nicht alle Felder sind abgeschlossen; nicht überwachte Felder werden vom Kernel auf Null gesetzt." und "In Linux 2.4 werden nur die Felder ru_utime, ru_stime, ru_minflt und ru_majflt gepflegt. Seit Linux 2.6 werden auch ru_nvcsw und ru_nivcsw gepflegt." –

1

Haben Sie versucht, eine Shared Library Interposer für Linux für Abschnitt (5) oben? Solange Ihre Anwendung die malloc-Funktionen nicht statisch verknüpft, können Sie eine neue Funktion zwischen Ihrem Programm und dem Kernel malloc einfügen. 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 eine malloc Einfügestück:

http://www.drdobbs.com/building-library-interposers-for-fun-and/184404926

Sie wahrscheinlich auch calloc und frei tun, werden Sie wollen. Anrufe auf neue Anrufe enden im Allgemeinen als Anruf bei malloc, so dass auch C++ abgedeckt ist.

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

http://tlrobinson.net/blog/2007/12/overriding-library-functions-in-mac-os-x-the-easy-way-dyld_insert_libraries/

--Matt