1. Overview

In this tutorial, we’ll explore four memory measurements used by processes in Linux; VSZ, RSS, USS, and PSS.

Each has its own characteristics and usages, as we’ll see when we go into details.

2. VSZ Memory

VSZ is short for Virtual Memory Size. It’s the total amount of memory a process may hypothetically access.

It accounts for the size of the binary itself, any linked libraries, and any stack or heap allocations.

When a process is started, VSZ memory becomes RSS memory, over which we’ll go now.

3. RSS Memory

As opposed to VSZ, RSS, also short for Resident Set Size, is a measurement that shows how much RAM has been allocated to a process during its execution.

But, it isn’t actually an accurate measurement for RAM usage for a process since it doesn’t take into account libraries already loaded in memory.

If two processes use one or more libraries, then RSS will report the libraries’ sizes for each process, even though the libraries would be already loaded beforehand in the case of one process starting after another. This is why RSS can be misleading and shouldn’t be trusted completely.

Because RSS shows the whole memory output, even for information that has already been preloaded, if we add up everything in the processes list, we’d get more memory than the total memory allocated.

4. Using RSS and VSZ

4.1. Using ps

One of the ways to check the RSS and VSZ for Linux processes is to call ps:

$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.1  0.0 169316 13184 ?        Ss   18:14   0:04 /sbin/init splash
root           2  0.0  0.0      0     0 ?        S    18:14   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   18:14   0:00 [rcu_gp]
// ...
root          28  0.0  0.0      0     0 ?        S    18:14   0:00 [idle_inject/3]

The output above is just a fraction of all the processes listed in the terminal.

But as we can see, we have two columns named RSS and VSZ, which show the total memory allocated to each process and the maximum a process has assigned to itself.

If we want to see only some processes (for example all Google Chrome processes), we can use:

ps eo user,pid,vsz,rss $(pgrep -f 'chrome')
USER                    PID     VSZ    RSS
baeldung-reader        5236 1358620 333984
baeldung-reader        5246  268300  63804
baeldung-reader        5247  268300  63084
// ...
baeldung-reader       36354 4587872  52700

4.2. Using top

Another useful command to check on processes is top. When we use it, it’ll display all the processes running in our system.

Unlike the command above, it checks every time for changes in the list of processes that run, so we can see changes in RSS and VSZ in real-time.

For example, if we look at the process with the PID 12408 (google chrome instance in this case), we can see the differences in, for example, %CPU which shows how much of the CPU that particular process is using. As we can see in the terminal, there are multiple chrome processes that run and it makes sense because there really are multiple processes that run – the actual chrome application, the opened tabs, maybe some downloads through the browser downloader, etc. – which are allocated more or fewer resources as the CPU sees fit:

top - 22:55:50 up  4:41,  1 user,  load average: 0,82, 2,25, 2,72
Tasks: 350 total,   1 running, 349 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0,5 us,  0,2 sy,  0,0 ni, 99,3 id,  0,0 wa,  0,0 hi,  0,0 si,  0,0 st
MiB Mem :  32035,2 total,  23820,8 free,   3484,8 used,   4729,7 buff/cache
MiB Swap:      0,0 total,      0,0 free,      0,0 used.  27832,6 avail Mem 

    PID USER                 PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
  // ...
  12408 baeldung-reader      20   0 9146156 312452 119532 S   1,7   1,0   9:56.70 chrome
  // ...
  12077 baeldung-reader      20   0 4784576 182196  92716 S   0,3   0,6   1:00.59 chrome

And 30 seconds later:

top - 22:56:20 up  4:41,  1 user,  load average: 0,63, 2,07, 2,65
Tasks: 351 total,   1 running, 350 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1,8 us,  0,5 sy,  0,0 ni, 97,7 id,  0,0 wa,  0,0 hi,  0,0 si,  0,0 st
MiB Mem :  32035,2 total,  23806,6 free,   3492,9 used,   4735,7 buff/cache
MiB Swap:      0,0 total,      0,0 free,      0,0 used.  27819,3 avail Mem 

    PID USER                 PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
  // ...
  12408 baeldung-reader      20   0 9185940 306080 123896 S  14,0   0,9  10:00.01 chrome
  // ...
   4340 baeldung-reader      20   0 1171680 328412 156400 S   1,3   1,0   6:15.76 chrome
  // ...
   4579 baeldung-reader      20   0 4723180 172064  73352 S   0,7   0,5   0:23.38 chrome
  // ...
   4414 baeldung-reader      20   0  377528 105756  66972 S   0,3   0,3   1:33.44 chrome
   4457 baeldung-reader      20   0  431860 120172  86228 S   0,3   0,4  20:52.63 chrome
  12691 baeldung-reader      20   0 4737484 173728  99572 S   0,3   0,5   0:15.66 chrome
  // ...

Again, this is just a fraction of the output, but we can see the volatility in change and the processes that are ordered out by the CPU which are prioritized and deprioritized.

As we mentioned before, these types aren’t completely accurate, but we can get a reliable estimate.

5. PSS Memory

PSS, or Proportional Set Size, is a much more useful memory management metric. It works exactly like RSS, but with the added difference of partitioning shared libraries.

For example, if we have five processes using the same library with a size of 50 pages, for each process the size reported by PSS will have only 10 pages for that particular shared library. The same thing happens for all shared libraries for all shared processes.

One advantage of PSS is that summing all the processes together, we get a good approximation of the whole memory usage in a system.

6. USS Memory

The Unique Set Size, or USS, represents the private memory of a process. In other words, it shows libraries and pages allocated only to this process.

This type of memory is also very useful, as it represents the actual cost of launching another process. And, vice versa, when a process ends, it represents the actual amount that is returned to the system.

7. Using PSS and USS

7.1. Using ps

To check the PSS memory on a Linux process, we have to access the /proc/{$PID}/smaps of the process we want to check. For this, we need the PID of the process we want to check.

For example, if we want to check on the rabbitmq-server process:

$ ps -aux | grep 'rabbitmq-server'
rabbitmq    1055  0.0  0.0   2608   604 ?        Ss   iun04   0:00 /bin/sh /usr/sbin/rabbitmq-server
$ sudo cat /proc/1055/smaps | grep -w 'Pss:'
Pss:                  20 kB
Pss:                  76 kB
Pss:                  24 kB
// ...
Pss:                   0 kB

Here, we will see multiple PSS outputs, which if we add we obtain the total PSS print of the process. Or, instead of adding lots of numbers, we can do this:

$ sudo cat /proc/1055/smaps | grep -i 'Pss:' |  awk '{Total+=$2} END {print Total}'
165

Here we have the total PSS memory size of the rabbitmq-server process reported in KB. If we have a process that uses lots of PSS memory, we can format the output to report it in a bigger measurement unit:

$ sudo cat /proc/1055/smaps | grep -i 'Pss:' | awk '{Total+=$2} END {print Total/1000" MB"}'
0,165 MB

We just need to remember to divide by 1000’s, not 1024’s because that’s the difference between Kilo and Mega.

7.2. Using smem

A very interesting tool we use to check for USS is smem, which we use to output USS and other types:

$ sudo apt-get install smem
$ smem
  PID User                Command                         Swap      USS      PSS      RSS 
 4346 baeldung-reader     cat                                0      116      149     1936 
 4347 baeldung-reader     cat                                0      120      151     1884 
 2663 baeldung-reader     /usr/libexec/gnome-session-        0      488      522     5240 
 2578 baeldung-reader     /usr/libexec/xdg-permission        0      748      794     6320 
 2558 baeldung-reader     /usr/bin/dbus-daemon --conf        0      668      812     4672 
 2820 baeldung-reader     /usr/libexec/gsd-screensave        0      788      832     6404 
 2531 baeldung-reader     /usr/libexec/ibus-memconf          0      776      859     7148 
 2803 baeldung-reader     /usr/libexec/gsd-a11y-setti        0      832      885     6728 
 2551 baeldung-reader     /usr/libexec/at-spi-bus-lau        0      824      893     7284 
 3192 baeldung-reader     /usr/libexec/gvfsd-metadata        0      860      902     6376 
 2498 baeldung-reader     /usr/libexec/gvfs-mtp-volum        0      860      906     6544 
 2431 baeldung-reader     /usr/libexec/gvfs-goa-volum        0      904      990     6644

To check a certain process, we make use again of the grep command:

$ smem | grep -w 'chrome'
60608 ioan     grep --color=auto -w chrome        0      364      396     2588 
 4381 ioan     /opt/google/chrome/nacl_hel        0      604     1121     4132 
 4376 ioan     /opt/google/chrome/nacl_hel        0      668     1183     4204 
 4379 ioan     /opt/google/chrome/chrome -        0      204     1232    15752 
// ...
 4340 ioan     /opt/google/chrome/chrome          0   276260   290467   387636

8. Conclusion

In this article, we saw how we can use the different memory measurements of Linux processes.

We also learned when to choose one over another and what they mean.