Bagaimana cara mendapatkan penggunaan memori saat runtime menggunakan C ++?

90

Saya perlu mendapatkan penggunaan mem VIRT dan RES pada saat program saya dijalankan dan menampilkannya.

Apa yang saya coba sejauh ini:

getrusage ( http://linux.die.net/man/2/getrusage )

int who = RUSAGE_SELF; 
struct rusage usage; 
int ret; 

ret=getrusage(who,&usage);

cout<<usage.ru_maxrss;

tapi saya selalu mendapatkan 0.

jww
sumber
3
Ini bergantung pada sistem - tampaknya sistem Anda tidak mendukung pelaporan maxrss melalui getrusage - dapatkah Anda memberi tahu kami distribusi apa yang Anda gunakan?
tvanfosson

Jawaban:

79

Di Linux, saya tidak pernah menemukan solusi ioctl () . Untuk aplikasi kami, kami membuat kode rutin utilitas umum berdasarkan membaca file di / proc / pid . Ada beberapa file ini yang memberikan hasil yang berbeda. Inilah yang kami selesaikan (pertanyaannya diberi tag C ++, dan kami menangani I / O menggunakan konstruksi C ++, tetapi harus mudah beradaptasi dengan rutinitas C i / o jika Anda perlu):

#include <unistd.h>
#include <ios>
#include <iostream>
#include <fstream>
#include <string>

//////////////////////////////////////////////////////////////////////////////
//
// process_mem_usage(double &, double &) - takes two doubles by reference,
// attempts to read the system-dependent data for a process' virtual memory
// size and resident set size, and return the results in KB.
//
// On failure, returns 0.0, 0.0

void process_mem_usage(double& vm_usage, double& resident_set)
{
   using std::ios_base;
   using std::ifstream;
   using std::string;

   vm_usage     = 0.0;
   resident_set = 0.0;

   // 'file' stat seems to give the most reliable results
   //
   ifstream stat_stream("/proc/self/stat",ios_base::in);

   // dummy vars for leading entries in stat that we don't care about
   //
   string pid, comm, state, ppid, pgrp, session, tty_nr;
   string tpgid, flags, minflt, cminflt, majflt, cmajflt;
   string utime, stime, cutime, cstime, priority, nice;
   string O, itrealvalue, starttime;

   // the two fields we want
   //
   unsigned long vsize;
   long rss;

   stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
               >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
               >> utime >> stime >> cutime >> cstime >> priority >> nice
               >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest

   stat_stream.close();

   long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
   vm_usage     = vsize / 1024.0;
   resident_set = rss * page_size_kb;
}

int main()
{
   using std::cout;
   using std::endl;

   double vm, rss;
   process_mem_usage(vm, rss);
   cout << "VM: " << vm << "; RSS: " << rss << endl;
}
Don Wakefield
sumber
Apakah Anda memiliki jaminan tentang struktur / proc / self / stat di bawah platform * nix yang berbeda? ... Saya tidak yakin, tetapi jika ya - itu akan menyenangkan.
bayda
Selama bertahun-tahun saya banyak menggunakan Solaris, HP-UX dan Linux. / proc / self / stat tampaknya merupakan Linux-ism. Versi asli dari program di atas memiliki #if blok untuk Solaris karena berbeda.
Don Wakefield
Saya berasumsi OP hanya peduli tentang Linux berdasarkan penandaan pertanyaan. Membaca / proc akan sebaik yang Anda dapatkan. Di Solaris, Anda juga bisa mendapatkan informasi tentang segala macam hal melalui kstat (meskipun sering kali mereplikasi apa yang bisa Anda peroleh dengan cara lain).
stsquad
Saya hanya terlambat 10 tahun ke pesta, tetapi maukah Anda memberi tahu saya mengapa Anda membagi vsize dengan 1024.0 daripada 1024?
a_river_in_canada
1
re: why 1024.0?- Ia memberitahu compiler untuk mengkonversi ke double FIRST dan kemudian melakukan pembagian untuk mendapatkan hasil double. Pilihan lainnya: vm_usage = vsize / 1024;akan melakukan pembagian terlebih dahulu, (kehilangan presisi seperti yang diisyaratkan @DonWakefield) dan kemudian ubah menjadi dua kali lipat.
Jesse Chisholm
52

David Robert Nadeau telah menempatkan fungsi C multi-platform mandiri yang baik untuk mendapatkan ukuran set residen proses (penggunaan memori fisik) di situsnya:

/*
 * Author:  David Robert Nadeau
 * Site:    http://NadeauSoftware.com/
 * License: Creative Commons Attribution 3.0 Unported License
 *          http://creativecommons.org/licenses/by/3.0/deed.en_US
 */

#if defined(_WIN32)
#include <windows.h>
#include <psapi.h>

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <sys/resource.h>

#if defined(__APPLE__) && defined(__MACH__)
#include <mach/mach.h>

#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
#include <fcntl.h>
#include <procfs.h>

#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
#include <stdio.h>

#endif

#else
#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
#endif





/**
 * Returns the peak (maximum so far) resident set size (physical
 * memory use) measured in bytes, or zero if the value cannot be
 * determined on this OS.
 */
size_t getPeakRSS( )
{
#if defined(_WIN32)
    /* Windows -------------------------------------------------- */
    PROCESS_MEMORY_COUNTERS info;
    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
    return (size_t)info.PeakWorkingSetSize;

#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
    /* AIX and Solaris ------------------------------------------ */
    struct psinfo psinfo;
    int fd = -1;
    if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
        return (size_t)0L;      /* Can't open? */
    if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
    {
        close( fd );
        return (size_t)0L;      /* Can't read? */
    }
    close( fd );
    return (size_t)(psinfo.pr_rssize * 1024L);

#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
    /* BSD, Linux, and OSX -------------------------------------- */
    struct rusage rusage;
    getrusage( RUSAGE_SELF, &rusage );
#if defined(__APPLE__) && defined(__MACH__)
    return (size_t)rusage.ru_maxrss;
#else
    return (size_t)(rusage.ru_maxrss * 1024L);
#endif

#else
    /* Unknown OS ----------------------------------------------- */
    return (size_t)0L;          /* Unsupported. */
#endif
}





/**
 * Returns the current resident set size (physical memory use) measured
 * in bytes, or zero if the value cannot be determined on this OS.
 */
size_t getCurrentRSS( )
{
#if defined(_WIN32)
    /* Windows -------------------------------------------------- */
    PROCESS_MEMORY_COUNTERS info;
    GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
    return (size_t)info.WorkingSetSize;

#elif defined(__APPLE__) && defined(__MACH__)
    /* OSX ------------------------------------------------------ */
    struct mach_task_basic_info info;
    mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
    if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
        (task_info_t)&info, &infoCount ) != KERN_SUCCESS )
        return (size_t)0L;      /* Can't access? */
    return (size_t)info.resident_size;

#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
    /* Linux ---------------------------------------------------- */
    long rss = 0L;
    FILE* fp = NULL;
    if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
        return (size_t)0L;      /* Can't open? */
    if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
    {
        fclose( fp );
        return (size_t)0L;      /* Can't read? */
    }
    fclose( fp );
    return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);

#else
    /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
    return (size_t)0L;          /* Unsupported. */
#endif
}

Pemakaian

size_t currentSize = getCurrentRSS( );
size_t peakSize    = getPeakRSS( );

Untuk pembahasan lebih lanjut, periksa situs web, ini juga menyediakan fungsi untuk mendapatkan ukuran memori fisik suatu sistem .

pepper_chico
sumber
2
sebaiknya tambahkan #pragma comment(lib, "psapi.lib")ke #if defined(_WIN32)ruang lingkup.
Bloodmoon
1
@Bloodmon bagaimana jika seseorang menggunakan windows tetapi bukan kompiler microsoft? Pragma itu akan membuat compiler gagal.
Adrian
Kode ini menggunakan rusage :: ru_maxrss dari getrusage, yang dilaporkan OP tidak berfungsi untuknya.
facetus
21

Tua:

maxrss menyatakan memori maksimum yang tersedia untuk proses tersebut. 0 berarti tidak ada batasan pada proses. Yang mungkin Anda inginkan adalah penggunaan data yang tidak digunakan bersama ru_idrss.

Baru: Tampaknya cara di atas tidak benar-benar berfungsi, karena kernel tidak mengisi sebagian besar nilai. Apa yang berhasil adalah mendapatkan informasi dari proc. Alih-alih menguraikannya sendiri, lebih mudah menggunakan libproc (bagian dari procps) sebagai berikut:

// getrusage.c
#include <stdio.h>
#include <proc/readproc.h>

int main() {
  struct proc_t usage;
  look_up_our_self(&usage);
  printf("usage: %lu\n", usage.vsize);
}

Kompilasi dengan " gcc -o getrusage getrusage.c -lproc"

Paul de Vrieze
sumber
1
Kecuali tidak ada bidang yang tersedia di Linux.
jmanning2k
2
Ini salah maxrss adalah penggunaan memori puncak dari proses tersebut, bukan maksimum yang tersedia - yang akan menjadi getrlimit (RLIMIT_DATA, & rl).
jmanning2k
1
The #include <proc/readproc.h>solusi bekerja besar bagi saya di bawah Ubuntu. Saya harus menginstal paket libproc-dev. usage.vm_dataadalah perkiraan yang cukup dekat dengan apa yang saya butuhkan. Pilihan statistik memori Anda didokumentasikan di sini: /usr/include/proc/readproc.hYang saya coba semuanya tampaknya dalam byte, bukan halaman. Saya tidak berpikir proses saya menggunakan 46 juta halaman. Komentar bahwa solusi ini tidak berfungsi di Linux tampaknya salah kaprah.
Allan Stokes
2
Linker yang benar adalah: -lprocps
Sembiance
Berhasil, yang ini harus menjadi jawaban yang diterima!
Pekov
9

Di linux, jika Anda mampu membayar biaya waktu proses (untuk debugging), Anda dapat menggunakan valgrind dengan alat massif:

http://valgrind.org/docs/manual/ms-manual.html

Ini berat, tapi sangat berguna.

David Cournapeau
sumber
8

Cara yang lebih elegan untuk metode Don Wakefield:

#include <iostream>
#include <fstream>

using namespace std;

int main(){

    int tSize = 0, resident = 0, share = 0;
    ifstream buffer("/proc/self/statm");
    buffer >> tSize >> resident >> share;
    buffer.close();

    long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
    double rss = resident * page_size_kb;
    cout << "RSS - " << rss << " kB\n";

    double shared_mem = share * page_size_kb;
    cout << "Shared Memory - " << shared_mem << " kB\n";

    cout << "Private Memory - " << rss - shared_mem << "kB\n";
    return 0;
}
Qsiris
sumber
7

Jawaban yang ada lebih baik untuk bagaimana mendapatkan nilai yang benar, tapi setidaknya saya bisa menjelaskan mengapa getrusage tidak bekerja untuk Anda.

pria 2 getrusage:

Struktur di atas diambil dari BSD 4.3 Reno. Tidak semua kolom memiliki arti di Linux. Saat ini (Linux 2.4, 2.6) hanya kolom ru_utime, ru_stime, ru_minflt, ru_majflt, dan ru_nswap yang dipertahankan.

jmanning2k.dll
sumber
3

sebagai tambahan untuk cara
Anda, Anda dapat memanggil perintah ps sistem dan mendapatkan penggunaan memori dari outputnya.
atau baca info dari / proc / pid (lihat PIOCPSINFO struct)

bayda
sumber
PIOCPSINFO tidak benar-benar tersedia di Linux mana pun yang saya gunakan. Membaca dari / proc / pid cukup umum. Saya akan memposting kode contoh untuk Linux sebagai jawaban ...
Don Wakefield
struktur yes / proc / pid dapat berbeda di platform * nix yang berbeda, tetapi jika Anda memiliki PIOCPSINFO, tidak masalah. Saya pernah mengalami situasi ketika struktur ini tidak ditentukan pada beberapa versi solaris .. Saya telah menggunakan output ps dalam kasus ini.
bayda
2

Di sistem Anda ada file bernama /proc/self/statm . Sistem file proc adalah sistem file semu yang menyediakan antarmuka ke struktur data kernel. File ini berisi informasi yang Anda butuhkan dalam kolom dengan hanya bilangan bulat yang dipisahkan spasi.

Kolom no .:

  1. = total ukuran program (VmSize di / proc / [pid] / status)

  2. = ukuran set penduduk (VmRSS di / proc / [pid] / status)

Untuk info lebih lanjut lihat LINK .

Jakub Krawczuk
sumber
1

Saya menggunakan cara lain untuk melakukan itu dan kedengarannya realistis. Apa yang saya lakukan adalah saya mendapatkan PID dari proses tersebut dengan fungsi getpid () dan kemudian saya menggunakan file / proc / pid / stat. Saya yakin kolom ke-23 dari file stat adalah vmsize (lihat posting Don). Anda dapat membaca vmsize dari file dimanapun Anda butuhkan dalam kode. Jika Anda bertanya-tanya berapa banyak potongan kode yang dapat menggunakan memori, Anda dapat membaca file itu satu kali sebelum potongan itu dan sekali setelahnya dan Anda dapat menguranginya satu sama lain.


sumber
1

Berdasarkan solusi Don W., dengan variabel yang lebih sedikit.

void process_mem_usage(double& vm_usage, double& resident_set)
{
    vm_usage     = 0.0;
    resident_set = 0.0;

    // the two fields we want
    unsigned long vsize;
    long rss;
    {
        std::string ignore;
        std::ifstream ifs("/proc/self/stat", std::ios_base::in);
        ifs >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore
                >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore >> ignore
                >> ignore >> ignore >> vsize >> rss;
    }

    long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
    vm_usage = vsize / 1024.0;
    resident_set = rss * page_size_kb;
}
ϹοδεMεδιϲ
sumber
0

Saya sedang mencari aplikasi Linux untuk mengukur memori maksimum yang digunakan. valgrind adalah alat yang luar biasa, tetapi memberi saya lebih banyak informasi daripada yang saya inginkan. waktu tampaknya menjadi alat terbaik yang dapat saya temukan. Mengukur penggunaan memori "highwater" (RSS dan virtual). Lihat jawaban ini .

jtpereyda.dll
sumber