You’re looking at the resident memory – that is, the physical RAM consumed. See here for more info.
The virtual memory, however, is the memory consumed by your application, including the memory swapped out (to disk). You’ll see there’s a closer correspondance with the virtual memory and your -Xms settings.
What does Virtual memory size in top mean?
Virtual memory isn’t even necessarily memory. For example, if a process memory-maps a large file, the file is actually stored on disk, but it still takes up “address space” in the process.
Address space (ie. virtual memory in the process list) doesn’t cost anything; it’s not real. What’s real is the RSS (RES) column, which is resident memory. That’s how much of your actual memory a process is occupying.
But even that isn’t the whole answer. If a process calls fork(), it splits into two parts, and both of them initially share all their RSS. So even if RSS was initially 1 GB, the result after forking would be two processes, each with an RSS of 1 GB, but you’d still only be using 1 GB of memory.
Confused yet? Here’s what you really need to know: use the free command and check the results before and after starting your program (on the +/- buffers/cache line). That difference is how much new memory your newly-started program used.
- Virtual size: is the amount of address space that a process is managing. The virtual address space contains everything that the process can access through pointers (memory address references). For example, if your program gets access to the framebuffer of your video card, that memory is mapped to the process virtual space and receives an address that is stored to a pointer. Memory-mapped files and anonymous mappings are also accounted into the virtual address space size. Pretty much everything is in the virtual size. If you sum up the size of all address ranges listed in /proc/\<pid>/maps, it should return you roughly the same value of the virtual size.</pid>
- Resident size: is the amount of memory that belongs specifically to that process that is currently resident in memory. That means, the amount of memory that is not in swap. Note that parts of the process can be in swap memory even when the process is running. The operating system will pull these regions from the swap when the process tries to access it. This should include the heap, the stacks of all threads and other private mappings. If you look in /proc/\<pid>/maps, the [stack], [heap] and other anonymous mappings (those without file paths) are either swapped or accounted in the resident size.</pid>
Shared size: is the amount of memory that may belong to multiple processes. For example, if you have four instances of the same application loaded in memory, you will have four instances of the heap and at least four stacks, one for each process (this is the resident memory), but you will have only one instance of the binary code of the program and its libraries. This is the shared space. Not only it includes the program binary code and its libraries, but also localization files, read-only program data, SysV and POSIX shared memory segments, semaphores, etc… If you look in /proc/\<pid>/maps, most mappings tied to library and program files are shared.</pid>