The last class of variables are global ones, which the program allocates once, when first referenced, and which retain their value and memory allocation until the program terminates. They may be accessible throughout the entire program, or only within some limited scope, such as a
static variable in a C function. Either way, their method of storage is identical. Globals are allocated off of the heap, the same area of memory used by
malloc for dynamic memory allocation.
malloc is smart enough to keep track of the memory areas used by globals, so it will not try to give out that memory when a request comes in. Because global variables eat up memory and keep it throughout the entire program, avoid them except when absolutely necessary. For large objects that you don't need for the entire program, it is much better to allocate them dynamically, so that you can free them once you are done with them, so that you can reuse the memory for other purposes.
Swap memory, or virtual memory, is an effective method for extending memory capacity beyond the physical limits of the RAM chips installed in a machine. All modern operating systems can use swap memory, which uses a special file or partition on disk to act as an additional block of memory. Like normal RAM, swap memory blocks must be contiguous, so often operating systems reserve a special partition on the hard disk just for this purpose. Windows can use one or more swap files in the standard file system, but again, the storage used by each file must be completely unfragmented.
The user can specify the size of swap, usually about equal to the amount of RAM, but it is up to the operating system to decide when and how to actually make use of the swap memory. Most commonly, blocks will be swapped out to disk when they have not been accessed for a while, or when the OS thinks they may no longer be needed (for example, when a process becomes idle). It can swap them back in when necessary. Because disk memory is thousands of times slower than RAM, it is important that swapping in and out be kept to a minimum--it is no replacement for conventional RAM. To see the fraction of a process that is in virtual memory at any given time, use the
top utility and subtract the
RSS column from the
top will also display the amount of swap in use, free RAM, and more.
The previous article claimed that once a process allocates some memory, it hangs on to it until the process terminates, even if the memory is freed. As a result, memory usage of a process always goes up, never down, over time. One alternative, however, is to use shared memory. A good example of when you might use shared memory is if you had a large data table you wanted several processes to use, but only want to load up one copy in RAM. Using a shared memory space allows all of the processes to access it without storing multiple copies for each new process. Sometimes this may be the only feasible way to perform a task in RAM. Another possible use is for interprocess communication. One process may write data, such as status information, to the shared memory area, while another may read the data written and respond accordingly.
Shared memory is implemented at the operating system level through a handful of system calls, including
shmctl. The exact implementation may vary on different CPUs. For details, see the
man pages for these commands on your system. For a simple alternative to these system calls, you can use files in /tmp for (slower) interprocess communication, or a RAMDisk. A RAMDisk is simply a block of memory reserved to act like a filesystem. You can read and write files from and to it like any other disk partition, but because it lies in RAM, it is thousands of times faster than conventional disk. The only drawbacks are that you'll lose all of its contents when the machine reboots, and the RAM used will be unavailable for other purposes of course.
Memory Leaks and Garbage Collection
Memory leaks are the bane of any C/C++ programmer and often result in much frustration. A memory leak occurs when memory is allocated with
malloc (or similar) and not subsequently freed. There are three distinct types. A reachable memory leak refers to a block of allocated memory, with a pointer variable pointing to it, which is never freed when it is no longer needed. It could still be freed by simply adding a
free command to the code once it is no longer needed and is simply wasting resources. An innocuous leak is a reachable one that is only allocated once and is required throughout the entire program, such as a database connection object. It is simply not explicitly freed before the program exits, though the OS will still free it. A true leak is a block of memory that has no pointer variables still pointing to it. It is permanently lost, and cannot be freed from within the program. This type is always a result of programmer error. Thankfully, all modern operating systems automatically clean up any true leaks from a process when it terminates. If they did not, like some early versions of MS-DOS, then you would eventually run out of memory after running leaky software, even with no processes running, and would need to reboot.
A common misconception is that memory leaks are only a concern when using C/C++. This is simply untrue. A language such as Java has built-in garbage collection, which may give programmers a false sense of security that they need not worry about leaking memory. However, garbage collection only works on true leaks, as defined above. That is, once a variable goes out of scope, any blocks of memory associated with it will be freed if no other variables are referencing that block. As long as some reference to it remains, however, the block is kept intact and is effectively a memory leak. Additionally, the garbage collector is normally only activated when the process is idle, or explicitly called by the programmer, and so if a leak happens to be occurring in a busy section of code, the collector may never run before memory exhaustion occurs.
Usually, the first sign of a memory leak is a steady increase in the memory usage of a program over time. This may only be noticeable when the program is run with a specific set of arguments--it may appear to be fine for some sets of inputs, and not for others. Some leaks are obvious, quickly using up all system memory and resulting in a core dump or out-of-memory error. Others are more subtle, and it can be difficult to tell if there is really a memory leak or if all the memory used is legitimate.