0

This is platform dependent question for Linux. And if it matters, I'm asking specifically about pre-C++11.

I want to indirectly test a class's destructor by new and delete to see if all of the memory on the program's heap is deallocated, which could check for memory leaks.

object* x;        //pointer allocated on the stack
...               //measure available heap space
x = new object(); //allocated on the heap
delete x;         //deallocate that heap space
...               //measure again, see if it's the same

I understand that Valgrind has Massif (...is there a C++ library for Massif..?), and that I can even run a memory leak check on my entire program, but code changes. Unit tests are important, and it bugs me to death that I can't fully unit test all of my code.

What code can I write that would measure available heap space?

jww
  • 97,681
  • 90
  • 411
  • 885
  • 1
    I'd say that's the wrong approach -- "*available*" heap space is not a constant over time. The memory mapped to your process will change, as the allocator calls OS specific APIs like `sbrk()` and `mmap()`. So what's "available"? Only what's currently mapped to your process? Or all memory your process *could possibly* get mapped? The latter is even more complicated (linux overcommits, btw). The other way around could work (but of course implementation dependent): measure the amount of *used* heap space. –  Jul 07 '17 at 21:26
  • 1
    All in all, you'd probably be "happier" doing what everyone else does: use unit testing for your actual business logic and look for memory handling errors using a tool like `valgrind` regularly (call it an *integration test*) ;) –  Jul 07 '17 at 21:29
  • Related, see Qualys [The Stack Clash](https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash) and [Will malloc implementations return free-ed memory back to the system?](https://stackoverflow.com/q/2215259/608639) – jww Jul 07 '17 at 21:53
  • The typical solution is to run unit tests with [ASAN (address sanitizer)](https://github.com/google/sanitizers/wiki/AddressSanitizer) or as you said yourself, under valgrind. I am not sure why you want to measure it from within the program. Just run a unit test that creates and deletes the object and then tell your test driver to run that test under valgrind. – Ilya Popov Jul 07 '17 at 23:22
  • If you want to be able to track your heap usage without running in a separate debug environment (i.e. you don't like running under valgrind for whatever reason), you can overload the C++ new and delete operators to track and report how many bytes of memory your program has allocated at any given time. An example is here: http://www.almostinfinite.com/memtrack.html – Jeremy Friesner Jul 08 '17 at 03:26

1 Answers1

0

The distinction between stack and heap are somewhat vague in Linux. Stack is just memory, the top of which, is handed to a clone() call which creates the new task. This is true both for new processes and new threads. The allocator operators are wrappers around system calls brk/sbrk. Your best bet is to override the global operator new/operator new[] and operator delete/operator delete[] to do some sort of counting of the calls in such a way that you can examine it at run time.

A quick read through new expression can give you a good idea of order in which things happen when an object is created/destroyed (forgive me if you already know this) and operator new will tell the order in which allocators are looked up. I may be wrong about this, but in order to have all allocators go through the same point of requesting memory from the OS, even the class-specific operator new would have to eventually call global operator new.

Well, the class-specific ones could use the allocator to mmap memory to a file or shmget to map the object to some storage in shared memory, but in both of those cases it wouldn't be part of what is traditionally referred to as "the heap." The stack+heap both reside in what you see as "VIRT" memory when you run "top" in linux.

Short of that, the memory allocated by malloc and passed to the clone call (which, for instance, creates a new thread) to be the stack of a new thread will not be different from the memory used as heap.

Dmitry Rubanovich
  • 2,471
  • 19
  • 27
  • Thanks for the links, I'm still new to all of this, and I will definitely give them a read. I cede that I'm probably just looking for the wrong solution here, and I should probably do what @Ilya Popov suggested with Valgrind. Again, thanks for the answer. –  Jul 08 '17 at 17:14