0

I have a memory management problem in a C++ program. I reproduced my problem on a very small example. This example has no memory-leak (valgrind memcheck is ok).

I use a vector of pointers in a limited scope. In this scope, I append the vector and I can see memory rising (I print vsize and rss from /proc/self/stat).

I meet a problem when the limited scope ends. I think that memory would come back to its initial value because the vector has been cleaned and destroyed. In practise, vector's destruction has no effect on memory!

Furthermore, I could observe a weird side effect. If I do a stream action (eg. read a file) before the end of the limited scope, memory is freed!

Main Code:

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

using std::cout;
using std::endl;
using std::vector;
using std::string;
using std::ios_base;
using std::ifstream;

void process_mem_usage(double &virtualSize, double &residentSetSize);
void printVectInfo(vector<int*> &o);
void monitoring();
void clearVector(vector<int*> &v);
void readFile();

void clearVector(vector<int*> &v) {
    for (size_t i = 0; i < v.size(); ++i) delete v[i];
    v.clear();
    vector<int*> w;
    v.swap(w);
}

int main() {
    size_t N = 1<<20;
    cout << "Size = " << N << endl;

    monitoring();

    // Limited scope
    {
        // Tmp vector limited to the current local scope
        vector<int*> v;
        v.reserve(N);
        for (size_t i = 0; i < N; ++i) v.push_back(new int(i));
        printVectInfo(v);
        monitoring();

        clearVector(v);
        printVectInfo(v);

        // readFile(); // this instruction solve the memory problem (paranormal instruction?!?)
    }
    // Here, vector has been destroyed

    monitoring();

    return 0;
}

Other functions (not important to understand the problem):

void process_mem_usage(double &virtualSize, double &residentSetSize) {
    virtualSize = 0.0;
    residentSetSize = 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,
           tpgid, flags, minflt, cminflt, majflt, cmajflt,
           utime, stime, cutime, cstime, priority, nice,
           num_threads, 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
                >> num_threads >> itrealvalue >> starttime >> vsize >> rss;
    stat_stream.close();

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

void printVectInfo(vector<int*> &o) {
    cout << "------" << endl
         << "Vector: "
         << "size = " << o.size() << " / "
         << "capacity = " << o.capacity() << endl;
}

void monitoring() {
    double vsize, rss;
    usleep(1000000);
    process_mem_usage(vsize, rss);
    cout << "------" << endl
         << "Memory: "
         << "vsize = " << vsize << " / "
         << "rss = " << rss << endl;
}

void readFile() {
    ifstream myfile("src/tmpFile.txt", std::ios::binary);
    if (myfile.is_open()) myfile.close();
}

Result without readFile() instruction (showing the problem):

Size = 1048576
------
Memory: vsize = 12580 / rss = 1060
------
Vector: size = 1048576 / capacity = 1048576
------
Memory: vsize = 53512 / rss = 42244
------
Vector: size = 0 / capacity = 0
------
Memory: vsize = 45316 / rss = 34132

We can see an abnormal busy memory on the last monitoring.

Result with readFile() instruction (solve the problem):

Size = 1048576
------
Memory: vsize = 12580 / rss = 1060
------
Vector: size = 1048576 / capacity = 1048576
------
Memory: vsize = 53512 / rss = 42244
------
Vector: size = 0 / capacity = 0
------
Memory: vsize = 12580 / rss = 1488

We can see a small difference between begin and end busy memory, but memory snapshots are in the same order of magnitude. Result seems to be ok here.

Why there is differences of runtime?. Any help would be appreciated.

Details on my runtime context:

* gcc 4.6.3
* ubuntu 12.04 (x86-64)
Mantosh Kumar
  • 5,659
  • 3
  • 24
  • 48
Nicolas
  • 21
  • 1
  • When you allocate memory on the heap , its not guarenteed that u will get the memory back instantly when you free it . Its upto the OS to decide – sameer karjatkar Apr 24 '14 at 09:28
  • Use valgrind's heap profiler (massif) instead of the proc stats, and see [this question](http://stackoverflow.com/q/131303/212858) to understand why. – Useless Apr 24 '14 at 09:41
  • I didn't known it was a kernel responsibility... I will read carefully your link. Thank you very much! – Nicolas Apr 24 '14 at 10:47

0 Answers0