views:

814

answers:

5

I'm writing cross platform C++ code (Windows, Mac). Is there a way to check how much memory is in use by the current process? A very contrived snippet to illustrate:

unsigned long m0 = GetMemoryInUse();
char *p = new char[ random_number ];
unsigned long m1 = GetMemoryInUse();
printf( "%d bytes used\n", (m1-m0) );

Of course (m1-m0) should equal random_number, but I'm trying to do this on a more complicated level, including possible library calls that could allocate memory.

The following are not preferable:

  1. Use Valgrind (or its ilk)
  2. Use a custom memory allocator to track allocated memory.
+3  A: 
  • There is no portable way to do that.
  • For most Operating systems, there isn't even a reliable way to do it specific to that OS.
James Curran
You're probably right. I was just hopeful there was something I missed. :) I'll most likely just end up with a custom memory manager.
pbhogan
+1  A: 

you can use "memory pool" pattern.All objects in your program allocate/deallocate memory from this pool so you can learn how much memory you consume.

Qubeuc
+6  A: 

Here's some code I wrote to try to do this in a portable way. It's not perfect, but I think it should at least give a pointer to how to do this on each of several platforms.

(P.S. I use OSX and Linux regularly, and know this works well. I use Windows more rarely, so caveats apply to the Windows clause, but I think it's right.)

#ifdef __linux__
# include <sys/sysinfo.h>
#endif

#ifdef __APPLE__
# include <mach/task.h>
# include <mach/mach_init.h>
#endif

#ifdef _WINDOWS
# include <windows.h>
#else
# include <sys/resource.h>
#endif

/// The amount of memory currently being used by this process, in bytes.
/// By default, returns the full virtual arena, but if resident=true,
/// it will report just the resident set in RAM (if supported on that OS).
size_t memory_used (bool resident=false)
{
#if defined(__linux__)
    // Ugh, getrusage doesn't work well on Linux.  Try grabbing info
    // directly from the /proc pseudo-filesystem.  Reading from
    // /proc/self/statm gives info on your own process, as one line of
    // numbers that are: virtual mem program size, resident set size,
    // shared pages, text/code, data/stack, library, dirty pages.  The
    // mem sizes should all be multiplied by the page size.
    size_t size = 0;
    FILE *file = fopen("/proc/self/statm", "r");
    if (file) {
        unsigned long vm = 0;
        fscanf (file, "%ul", &vm);  // Just need the first num: vm size
        fclose (file);
       size = (size_t)vm * getpagesize();
    }
    return size;
#endif

#elif defined(__APPLE__)
    // Inspired by:
    // http://miknight.blogspot.com/2005/11/resident-set-size-in-mac-os-x.html
    struct task_basic_info t_info;
    mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
    task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count);
    size_t size = (resident ? t_info.resident_size : t_info.virtual_size);
    return size;

#elif defined(_WINDOWS)
    // According to MSDN...
    PROCESS_MEMORY_COUNTERS counters;
    if (GetProcessMemoryInfo (GetCurrentProcess(), &count, sizeof (count)))
        return count.PagefileUsage;
    else return 0;

#else
    // No idea what platform this is
    return 0;   // Punt
#endif
}
Larry Gritz
Looks like a good answer to me :)
Andrew Rollings
You have a stray #endif on the line before #elif defined(__APPLE__).
Judge Maygarden
Also, the first #else only applies to #ifdef _WINDOWS...
Judge Maygarden
Unfortunately it doesn't seem to work. :(The more I dig, the more it seems there is no good way to do it short of a custom memory manager.
pbhogan
@pbhoganI would stick to platform dependent code like above. The code above is a bit messed up but it should provide you with a good start (windows part has a error in it - counters != count, see http://msdn.microsoft.com/en-us/library/ms683219(VS.85).aspx and the linked example).
Hrvoje Prgeša
@pbhogan As for custom memory manager that wouldn't give you the stack size, system reserved memory, library allocated memory and so on... Is it a new project? Why do you need this?
Hrvoje Prgeša
+2  A: 

I've used SIGAR API to get all sorts of system related info quite portably across major platforms. It's open source (GPL) as well. There is really no need to reinvent the wheel on these relatively trivial but tedious work.

ididak
A: 

Check out mallinfo().

Andrew