Here again the the resource limits come to rescue. But the more useful thing that stand by our side is proc - a file system that contains process information.

proc is the key to determining memory usage by a program. It is an interface to kernel data structures and is usually mounted at /proc in a UNIX-based machine. See `man proc` for more detail.

For almost every process running in the system, there is a directory created in /proc/. The directory name is the process id and it contains several useful files which convey important information. The two main files of concern here are:

/proc/[pid]/status: This file has crucial information regarding memory usage such as virtual memory size (VmSize), size of data segment (VmData), stack size (VmStk), and size of text segment (VmExe). These sizes are in KB i.e. KiloBytes which is what often required for the online judge to determinte the memory usage. (data segment is actually data+bss+heap - which is often confusing!)

/proc/[pid]/statm: This files also contains information about memory usage. The files has a single row of information where values are placed separated by space. These values are total program size, resident set size, size of shared pages, size of text segment, size of lib code, size of data segment + stack, and dirty pages.

The caveat is that this size information in /proc/[pid]/statm is in terms of number of pages. But you can easily get the size in KB by multiplying the number of pages by 4, assuming in your machine 1 page equals to 4KBs which is usually the case and that is the value at least in my machine. (I really don't know how it varies across different machines or OS!)

Now with all this information, the question comes which values (data or stack or text or combination of some of them) to consider for determining the memory usage of a process. Before continuing let's have a look at the address space of a program:

Now the memory we are interested in computing is the sum total of size of data, bss, heap and stack. VmData in /proc/[pid]/status is the size of data+bss+heap, and VmStk is the size of stack - both values in Kilo Bytes. Simply adding VmData nd VmStk gives us the memory usage of the process.

VmData is sometimes inaccurate as the heap size is inaccurate. Sometimes the kernel allocates more memory than asked for optimization and the remaining memory is used when demanded later. But AFAIK they happen when large amount of dynamic memory is allocated by the process via syscalls suck as brk(). Also sometimes the heap memory is not used and an anonymous memory mapping is created for large block of memory requested via malloc().

Below is a piece of code that shows how to do this. It just contains the portion of interest and you may have to add/modify many parts to suit your need.

It is worthwhile to note here that the resource limits are preserved across execve. So the user-supplied program exec'ed in the child process inherits the resource limits. Setting RLIMIT_STACK and RLIMIT_RSS to appropriate values also help in limiting the memory usage of a process.

The only function in above code which needs to be implemented isget_memory_usage().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

int get_memory_usage(pid_t pid) {

int fd, data, stack;

char buf[4096], status_child[NAME_MAX];

char *vm;

sprintf(status_child, "/proc/%d/status", pid);

if ((fd = open(status_child, O_RDONLY)) < 0)

return -1;

read(fd, buf, 4095);

buf[4095] = '\0';

close(fd);

data = stack = 0;

vm = strstr(buf, "VmData:");

if (vm) {

sscanf(vm, "%*s %d", &data);

}

vm = strstr(buf, "VmStk:");

if (vm) {

sscanf(vm, "%*s %d", &stack);

}

return data + stack;

}

This implementation of get_memory_usage() has used /proc/[pid]/status. You can also read from /proc/[pid]/statm, and multiply the penultimate value (number of pages in data+bss+heap+stack) by the page size.

There may be more accurate ways than this for measuring memory usage and I would love to know about them.

A few worthy points can be noted here:

VmRSS in /proc/[pid]/statm is a useful data. It shows how much memory in RAM is occupied by the process. The rest extra memory has either been not used or has been swapped out.

VmSize is how much virtual memory the process has in total. This includes all types of memory, both in RAM and swapped out. These numbers can get skewed because they also include shared libraries.

We can determine the memory used by stack and heap from /proc/[pid]/smaps. Searching for the keywords `heap` and `stack` returns two lines of information - the first value in each line is the range of addresses in heap and stack respectively. This address is in hexadecimal. So to calculate the size we can simply subtract the higher value to lower value, convert the result to decimal form and divide by 4*1024 to get the size in Kilo Bytes.

Comments

Thanks for your ideas. You can also find the details on Affity Solutions, at the C++ Developers. The main object of the Affity Solutions is to provide quality web services and is among the few software development company in Nagpur.