C ++ kullanarak çalışma zamanında bellek kullanımı nasıl elde edilir?


90

Programımın çalışma zamanında mem kullanımını VIRT ve RES almam ve görüntülemem gerekiyor.

Şimdiye kadar denediğim şey:

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;

ama her zaman 0 alırım.


3
Bu sisteme bağlıdır - görünüşe göre sisteminiz getrusage aracılığıyla maxrss raporlamayı desteklemiyor - bize hangi dağıtımı kullandığınızı söyleyebilir misiniz?
tvanfosson

Yanıtlar:


79

Linux'ta hiç bir ioctl () çözümü bulamadım . Uygulamalarımız için / proc / pid içindeki dosyaları okumaya dayalı genel bir yardımcı program rutini kodladık . Farklı sonuçlar veren bu dosyalardan birkaçı vardır. İşte kararlaştırdığımız soru (soru C ++ olarak etiketlendi ve G / Ç'yi C ++ yapıları kullanarak ele aldık, ancak gerekirse C i / o rutinlerine kolayca uyarlanabilmelidir):

#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;
}

farklı * nix platformları altında / proc / self / stat yapısı hakkında herhangi bir garantiniz var mı? ... emin değilim, ama evet ise - güzel olacak.
bayda

Yıllar boyunca çoğunlukla Solaris, HP-UX ve Linux kullandım. / proc / self / stat bir Linux-ism gibi görünüyor. Yukarıdaki programın orijinal sürümü, farklı olduğu için Solaris için #if bloklarına sahipti.
Don Wakefield

OP'nin soru etiketlemeye dayalı olarak yalnızca Linux'u önemsediğini varsayıyorum. Okuma / proc, aldığınız kadar iyi olacak. Solaris'te ayrıca her türlü şeyle ilgili bilgileri kstat aracılığıyla alabilirsiniz (her ne kadar genellikle başka yollarla elde edebileceğinizin aynısını oluştursa da).
stsquad

Partiye sadece 10 yıl geç kaldım, ama neden vsize 1024 yerine 1024.0'a böldüğünüzü söyler misiniz?
a_river_in_canada

1
re: why 1024.0?- Derleyiciye çift İLK'e dönüştürmesini ve ardından çift sonucu almak için bölmeyi yapmasını söyler. Diğer seçenek: vm_usage = vsize / 1024;önce bölmeyi yapacaktı (@ DonWakefield olarak hassasiyeti kaybederek) ve sonra ikiye katlayacaktı.
Jesse Chisholm

52

David Robert Nadeau , kendi web sitesinde işlem yerleşik seti boyutunu (fiziksel bellek kullanımı) elde etmek için iyi bir bağımsız çoklu platform C işlevi koydu:

/*
 * 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
}

Kullanım

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

Daha fazla tartışma için, web sitesini kontrol edin, ayrıca bir sistemin fiziksel bellek boyutunu alma işlevi de sağlar .


2
kapsama eklemesi daha iyi #pragma comment(lib, "psapi.lib")olur #if defined(_WIN32).
Bloodmoon

1
@Bloodmon peki ya birisi windows kullanıyorsa ancak microsoft derleyicisi kullanmıyorsa? Bu pragma derleyiciyi başarısız kılar.
Adrian

Bu kod, OP'nin kendisi için çalışmadığını bildirdiği getrusage'dan rusage :: ru_maxrss kullanır.
facetus

22

Eski:

maxrss, işlem için kullanılabilir maksimum belleği belirtir. 0, sürece herhangi bir sınır konulmadığı anlamına gelir. Muhtemelen istediğiniz şey paylaşılmamış veri kullanımıdır ru_idrss.

Yeni: Çekirdek değerlerin çoğunu doldurmadığından yukarıdakiler aslında çalışmıyor gibi görünüyor. İşe yarayan şey, bilgiyi proc'tan almaktır. Kendini ayrıştırmak yerine libproc'u (procps'un bir parçası) aşağıdaki gibi kullanmak daha kolaydır:

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

" gcc -o getrusage getrusage.c -lproc" İle derleyin


1
Her iki alanın dışında Linux'ta mevcut değildir.
jmanning2k

2
Bu yanlış. maxrss, sürecin en yüksek bellek kullanımıdır, mevcut maksimum değil - bu getrlimit olacaktır (RLIMIT_DATA, & rl).
jmanning2k

2
#include <proc/readproc.h>Çözelti Ubuntu altında benim için çok çalıştı. Paketi yüklemem gerekiyordu libproc-dev. usage.vm_dataihtiyacım olana yeterince yakın bir yaklaşım. Bellek istatistiği seçiminiz burada belgelenmiştir: /usr/include/proc/readproc.hTüm denediklerim sayfalar değil bayt cinsindendir. Sürecimin 46 milyon sayfa kullandığını sanmıyorum. Bu çözümün Linux altında çalışmadığı yorumları yanlış görünüyor.
Allan Stokes

2
Doğru bağlayıcı: -lprocps
Sembiance

1
Harika çalışıyor, bu kabul edilen cevap olmalı!
Pekov


8

Don Wakefield yöntemi için daha zarif bir yol:

#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;
}

7

Doğru değeri nasıl elde edeceğiniz konusunda mevcut cevaplar daha iyidir, ancak en azından getrusage'ın sizin için neden işe yaramadığını açıklayabilirim.

2. adam getrusage:

Yukarıdaki yapı, BSD 4.3 Reno'dan alınmıştır. Linux altında tüm alanlar anlamlı değildir. Şu anda (Linux 2.4, 2.6) sadece ru_utime, ru_stime, ru_minflt, ru_majflt ve ru_nswap alanları korunmaktadır.


3

yolunuza ek olarak
sistem ps komutunu çağırabilir ve ondan bellek kullanımı elde edebilirsiniz.
veya / proc / pid'den bilgi okuyun (bkz. PIOCPSINFO yapısı)


PIOCPSINFO, kullandığım herhangi bir Linux'ta gerçekten mevcut değil. / Proc / pid'den okumak oldukça yaygındır. Bir cevapta Linux için örnek kod göndereceğim ...
Don Wakefield

yes / proc / pid yapıları farklı * nix platformlarında farklı olabilir, ancak PIOCPSINFO'nuz varsa bunun bir önemi yoktur. Bazı solaris sürümlerinde bu yapının tanımlanmadığı bir durum yaşadım .. Bu durumda ps çıktısını kullandım.
bayda

2

Sisteminizde adlı bir dosya var /proc/self/statm. Proc dosya sistemi, çekirdek veri yapılarına bir arayüz sağlayan sözde bir dosya sistemidir. Bu dosya, ihtiyacınız olan bilgileri yalnızca boşlukla ayrılmış tamsayılar içeren sütunlarda içerir.

Sütun no .:

  1. = toplam program boyutu (/ proc / [pid] / status içinde VmSize)

  2. = yerleşik set boyutu (/ proc / [pid] / status içindeki VmRSS)

Daha fazla bilgi için LINK'e bakın .


1

Bunu yapmak için başka bir yol kullanıyorum ve kulağa gerçekçi geliyor. Yaptığım şey, işlemin PID'sini getpid () işlevi ile aldım ve sonra / proc / pid / stat dosyasını kullanıyorum. İstatistik dosyasının 23. sütununun vmsize olduğuna inanıyorum (Don gönderisine bakın). Kodda ihtiyacınız olan her yerde vmsize dosyasını dosyadan okuyabilirsiniz. Bir kod parçacığının belleği ne kadar kullandığını merak ediyorsanız, o dosyayı o parçacığından önce ve sonra bir kez okuyabilir ve bunları birbirinden çıkarabilirsiniz.


1

Don W'nin daha az değişkenli çözümüne dayanmaktadır.

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

0

Kullanılan maksimum belleği ölçmek için bir Linux uygulaması arıyordum. valgrind mükemmel bir araç, ancak bana istediğimden daha fazla bilgi veriyordu. tstime bulabildiğim en iyi araç gibi görünüyordu. "Yüksek su" bellek kullanımını ölçer (RSS ve sanal). Bu cevaba bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.