Làm thế nào để sử dụng bộ nhớ trong thời gian chạy bằng C ++?


90

Tôi cần lấy VIRT và RES sử dụng mem tại thời gian chạy chương trình của mình và hiển thị chúng.

Những gì tôi đã thử cho đến nay:

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;

nhưng tôi luôn nhận được 0.


3
Điều này phụ thuộc vào hệ thống - có vẻ như hệ thống của bạn không hỗ trợ báo cáo maxrss qua getrusage - bạn có thể cho chúng tôi biết bạn đang sử dụng bản phân phối nào không?
tvanfosson

Câu trả lời:


79

Trên Linux, tôi chưa bao giờ tìm thấy giải pháp ioctl () . Đối với các ứng dụng của mình, chúng tôi đã viết mã một quy trình tiện ích chung dựa trên việc đọc các tệp trong / proc / pid . Có một số tệp này cho kết quả khác nhau. Đây là câu hỏi mà chúng tôi đã giải quyết (câu hỏi được gắn thẻ C ++ và chúng tôi xử lý I / O bằng cách sử dụng các cấu trúc C ++, nhưng nó sẽ dễ dàng thích ứng với các quy trình C i / o nếu bạn cần):

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

bạn có đảm bảo gì về cấu trúc / proc / self / stat dưới các nền tảng * nix khác nhau không? ... Tôi không chắc, nhưng nếu có - nó sẽ tốt.
bayda

Chà, trong những năm qua, tôi chủ yếu sử dụng Solaris, HP-UX và Linux. / proc / self / stat có vẻ là một Linux-ism. Phiên bản gốc của chương trình ở trên có #if khối cho Solaris vì nó khác.
Don Wakefield

Tôi cho rằng OP chỉ quan tâm đến Linux dựa trên việc gắn thẻ câu hỏi. Đọc / proc sẽ tốt như bạn nhận được. Trên Solaris, bạn cũng có thể lấy thông tin về tất cả các loại thông qua kstat (mặc dù nó thường sao chép những gì bạn có thể nhận được thông qua các phương tiện khác).
stsquad

Tôi chỉ mới dự tiệc 10 năm, nhưng bạn có phiền cho tôi biết tại sao bạn chia vsize cho 1024.0 thay vì 1024 không?
a_river_in_canada

1
re: why 1024.0?- Nó yêu cầu trình biên dịch chuyển đổi thành double FIRST và sau đó thực hiện phép chia để nhận được kết quả kép. Sự lựa chọn khác: vm_usage = vsize / 1024;sẽ thực hiện phép chia trước, (mất độ chính xác khi @DonWakefield được thân mật) và sau đó chuyển đổi thành nhân đôi.
Jesse Chisholm,

52

David Robert Nadeau đã đưa một hàm C đa nền tảng độc lập tốt để có được kích thước thiết lập cư trú của quy trình (sử dụng bộ nhớ vật lý) trong trang web của mình:

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

Sử dụng

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

Để thảo luận thêm, hãy kiểm tra trang web, nó cũng cung cấp một chức năng để lấy kích thước bộ nhớ vật lý của một hệ thống .


2
tốt hơn đã thêm #pragma comment(lib, "psapi.lib")vào #if defined(_WIN32)phạm vi.
Tuần trăng máu

1
@Bloodmon thì sao nếu ai đó đang sử dụng windows nhưng không phải trình biên dịch microsoft? Pragma đó sẽ làm cho trình biên dịch không thành công.
Adrian

Đoạn mã này sử dụng rusage :: ru_maxrss từ getrusage, mà OP đã báo cáo là không hoạt động với cô ấy.
facetus

21

Cũ:

maxrss cho biết bộ nhớ có sẵn tối đa cho quá trình. 0 có nghĩa là không có giới hạn nào được đưa ra cho quy trình. Những gì bạn có thể muốn là sử dụng dữ liệu không chia sẻ ru_idrss.

Mới: Có vẻ như cách trên không thực sự hoạt động, vì hạt nhân không điền vào hầu hết các giá trị. Công việc là lấy thông tin từ proc. Thay vì tự phân tích cú pháp, bạn có thể sử dụng libproc (một phần của đạo cụ) dễ dàng hơn như sau:

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

Biên dịch với " gcc -o getrusage getrusage.c -lproc"


1
Ngoại trừ trường không có sẵn trong Linux.
jmanning2k

2
Điều này là không chính xác. maxrss là mức sử dụng bộ nhớ cao nhất của quá trình, không phải mức tối đa khả dụng - đó sẽ là getrlimit (RLIMIT_DATA, & rl).
jmanning2k

1
Các #include <proc/readproc.h>giải pháp làm việc rất lớn đối với tôi dưới Ubuntu. Tôi đã phải cài đặt gói libproc-dev. usage.vm_datalà một giá trị xấp xỉ đủ gần với những gì tôi cần. Sự lựa chọn thống kê bộ nhớ của bạn được ghi lại ở đây: /usr/include/proc/readproc.hNhững cái tôi đã thử dường như đều tính bằng byte, không phải trang. Tôi không nghĩ rằng quá trình của tôi đã sử dụng 46 triệu trang. Các nhận xét rằng giải pháp này không hoạt động trên Linux có vẻ như là sai lầm.
Allan Stokes

2
Trình liên kết đúng là: -lprocps
Sembiance

Hoạt động tuyệt vời, cái này phải là câu trả lời được chấp nhận!
Pekov


8

Một cách thanh lịch hơn cho phương pháp 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;
}

7

Các câu trả lời hiện có sẽ tốt hơn cho cách nhận giá trị chính xác, nhưng ít nhất tôi có thể giải thích tại sao getrusage không hoạt động với bạn.

người đàn ông 2 getrusage:

Cấu trúc [rusage] trên được lấy từ BSD 4.3 Reno. Không phải tất cả các trường đều có ý nghĩa trong Linux. Hiện tại (Linux 2.4, 2.6) chỉ có các trường ru_utime, ru_stime, ru_minflt, ru_majflt và ru_nswap được duy trì.


3

Ngoài ra, theo cách của
bạn, bạn có thể gọi lệnh ps hệ thống và sử dụng bộ nhớ từ đầu ra của nó.
hoặc đọc thông tin từ / proc / pid (xem cấu trúc PIOCPSINFO)


PIOCPSINFO không thực sự khả dụng trên bất kỳ Linux nào tôi đã sử dụng. Đọc từ / proc / pid là khá phổ biến. Tôi sẽ gửi mã ví dụ cho Linux trong một câu trả lời ...
Don Wakefield

cấu trúc yes / proc / pid couls khác nhau trong các nền tảng * nix khác nhau, nhưng nếu bạn có PIOCPSINFO thì không vấn đề gì. Tôi đã gặp tình huống khi cấu trúc này không được xác định trên một số phiên bản solaris .. Tôi đã sử dụng đầu ra ps trong trường hợp này.
bayda

2

Trên hệ thống của bạn có một tệp được đặt tên /proc/self/statm. Hệ thống tệp proc là một hệ thống tệp giả cung cấp giao diện cho cấu trúc dữ liệu nhân. Tệp này chứa thông tin bạn cần trong các cột chỉ có các số nguyên được phân tách bằng dấu cách.

Cột số:

  1. = tổng kích thước chương trình (VmSize in / proc / [pid] / status)

  2. = kích thước tập hợp thường trú (VmRSS trong / proc / [pid] / trạng thái)

Để biết thêm thông tin, hãy xem LINK .


1

Tôi đang sử dụng cách khác để làm điều đó và nó có vẻ thực tế. Những gì tôi làm là tôi lấy PID của quy trình bằng hàm getpid () và sau đó tôi sử dụng tệp / proc / pid / stat. Tôi tin rằng cột thứ 23 của tệp stat là vmsize (nhìn vào bài đăng của Don). Bạn có thể đọc vmsize từ tệp ở bất cứ nơi nào bạn cần trong mã. Trong trường hợp bạn thắc mắc một đoạn mã có thể sử dụng bộ nhớ bao nhiêu, bạn có thể đọc tệp đó một lần trước đoạn mã đó và một lần sau đó và bạn có thể trừ chúng cho nhau.


1

Dựa trên giải pháp của Don W, với ít biến hơn.

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

Tôi đang tìm kiếm một ứng dụng Linux để đo bộ nhớ tối đa được sử dụng. valgrind là một công cụ tuyệt vời, nhưng đã cung cấp cho tôi nhiều thông tin hơn tôi muốn. tstime dường như là công cụ tốt nhất mà tôi có thể tìm thấy. Nó đo mức sử dụng bộ nhớ "highwater" (RSS và ảo). Xem câu trả lời này .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.