1. Introduction

As a Linux user, it’s essential to know how to monitor and manage memory usage to ensure our system runs smoothly. In this tutorial, we’ll discuss the basics of memory allocation and management in Linux, the types of memory, the memory hierarchy, and the tools available for monitoring memory usage per user.

2. Understanding Memory Usage in Linux

Before we dive into monitoring memory usage per user, it’s important we understand how memory allocation and management work in Linux.

2.1. Types of Memory

In Linux, there are two types of memory – physical memory and virtual memory. Physical memory, also known as RAM (Random Access Memory), is the actual physical memory installed on your computer.

On the other hand, virtual memory is an indirect abstraction the operating system provides that allows applications to access more memory than is physically available.

2.2. Memory Allocation in Linux

Linux uses virtual memory to allocate memory space to applications. Each application has its own virtual address space, which is used to store its code and data. The virtual address space is divided into two parts – the user space and the kernel space. Applications use user space, while the operating system uses kernel space.

When an application needs memory, it requests it from the kernel. Then, the kernel allocates memory from the physical memory or the swap space if the physical memory is full. The kernel also manages memory allocation and deallocation, ensuring that each application has access to the memory it needs.

3. Memory Hierarchy

The memory hierarchy is a way of organizing memory based on its speed and capacity. In Linux, the memory hierarchy consists of four levels, each with different characteristics that affect the performance of the system.

At the top of the hierarchy are registers, which are the fastest, smallest, and most expensive type of memory used by the CPU to store temporary data. Registers are built into the CPU itself and can be accessed almost instantly. However, they are also the most limited in terms of storage capacity and can only hold a small amount of data at a time.

Cache memory is the next level in the hierarchy and is a small amount of memory located on the CPU that stores frequently used data to improve performance. Like registers, cache memory is very fast but is also more expensive than other types of memory. The amount of cache memory varies depending on the CPU and can range from a few kilobytes to several megabytes.

The third level in the hierarchy is Random Access Memory (RAM), which is the main memory used by the system to store data and programs that are currently in use. RAM is much slower than registers and cache memory but has a much larger capacity. Also, RAM is volatile, which means that its contents are lost when the system is powered off.

Finally, the lowest level in the hierarchy is swap space. Swap space is a portion of the hard drive that stores data not currently in use in RAM. When the system runs out of available RAM, it moves some of the least-used data to the swap space to free up space in RAM for more important data. However, since accessing data from the hard drive is much slower than accessing data from RAM, using swap space can significantly slow down the system’s performance.

4. Memory Monitoring Tools in Linux

Memory monitoring is an essential aspect of system administration, especially when you need to troubleshoot issues related to memory usage. Fortunately, Linux provides various powerful tools for monitoring memory usage effectively, including the top, ps, pmap, and smem tools.

5. Checking Memory Usage per User

Now that we understand the basics of memory usage in Linux and the tools available for monitoring it let’s dive into how to check memory usage per user in Linux.

5.1. Using the top Tool

The top command is a standard Unix/Linux tool for monitoring system resources, including memory usage. We can use it to view the memory usage of a specific user:

$ top -b -n 1 -u username

Here, -b runs the command in batch mode, -n 1 specifies the number of iterations, and -u filters by username. We can replace username with the actual user we want to check.

Then, its output will display the memory usage statistics for each process owned by the specified user:

PID     USER    PR   NI   VIRT     RES     SHR  S   %CPU  %MEM    TIME+     COMMAND
1234    user1   20    0   123456   65432   12345 S   0.0   1.2    0:00.01   process1
5678    user1   20    0   789012   98765   54321 S   0.0   1.8    0:00.03   process2

From our output, we can see the memory usage statistics for each process owned by the specified user, including the Process ID (PID), Username (USER), Priority (PR), Nice value (NI), Virtual Memory Usage (VIRT), Resident Memory Usage (RES), Shared Memory Usage (SHR), Process Status (S), Percentage of CPU Usage (%CPU), Percentage of Memory Usage (%MEM), Total CPU time (TIME+), and lastly, Process Command (COMMAND).

Here, the RES column shows the actual physical memory used by each process, which we can add up to obtain the total memory usage for the specified user. From this example, we can conclude that user1 has two processes running with a total memory usage of 3.0% (%MEM) of the system’s available memory.

5.2. Using the ps Command

The ps tool is another command-line utility that provides information about running processes on a Linux system. We can also use it to get information about the memory usage of processes owned by a specific user:

$ ps -u username -o pid,%mem,command

In this command, -u filters by the username we provide, and -o specifies the output format.

Then, its output looks similar to our previous interaction:

 PID      %MEM    COMMAND
 1234      1.2    process1
 5678      1.8    process2

Here, %MEM represents the percentage of physical memory used by each process for the specific user. We can sum up these values to obtain the total memory usage for the specified user. In this example, a total physical memory usage of 3.0% (%MEM) of the system’s available memory.

Alternatively, we can use a Bash script that uses the ps command to show the total memory usage per user:

#!/bin/bash

(echo "user rss(KiB) vmem(KiB)";
 for user in $(users | tr ' ' '\n' | sort -u); do
   echo $user $(ps -U $user --no-headers -o rss,vsz \
     | awk '{rss+=$1; vmem+=$2} END{print rss" "vmem}')
 done | sort -k3
) | column -t

The script uses the ps command to print out the RSS and VSZ memory usage for each user on the system and uses awk to calculate the sum of these values for each user. Then, the output is sorted by VSZ in ascending order and formatted using the column command to align the columns.

Let’s see a sample execution of this script:

user      rss(KiB)  vmem(KiB)
root      265104    142850
jdoe      159432    617408
jsmith    283096    787764

The RSS (KiB) column indicates the Resident Set Size, the amount of physical memory used by each user’s processes in kilobytes, and the vmem (KiB) column indicates the total virtual memory used by the processes, also in kilobytes.

In this example output, there are three users listed – root, jdoe, and jsmith. The root user has the lowest VSZ and the second-highest RSS, while jsmith has the highest VSZ and the highest RSS. Therefore, the user jsmith has the highest memory usage on the system among the listed users.

5.3. Using the pmap Tool

Another tool we can use to view the memory usage per user is the pmap command:

$ pmap -x $(pgrep -u <username>)

In this command, $(pgrep -u ) finds the process IDs owned by the specified user, and -x specifies the extended format output.

Like earlier interactions, the output will display the memory usage statistics for each process owned by the specified user:

Address           Kbytes   RSS   Dirty Mode  Mapping
...
mapped: total      1234    5678     9012

Here, RSS represents the resident set size, the portion of the process’s memory held in RAM. The RSS column shows the actual physical memory used by each process, which we can add up to obtain the total memory usage for that user. The mapped: total line at the end of the output displays the total memory usage for all the processes owned by the specified user.

5.4. Using the smem Tool

The smem command is a tool for displaying memory usage statistics by the process. We can also use it to view the memory usage per user:

$ smem -u john

Here, -u filters by username (in this case, john):

User     Count     Swap      USS      PSS      RSS
john     23        0         315M     316M     473M

From our output, we can see the memory usage statistics for the user john. The Count column indicates the number of memory-mapped pages, the Swap column indicates the amount of swapped-out memory, and the USS, PSS, and RSS columns indicate the memory usage in the Unique Set Size (USS), Proportional Set Size (PSS), and Resident Set Size (RSS) respectively, measured in megabytes.

The USS, PSS, and RSS columns represent the memory usage in different ways and we can add them up to obtain the total memory usage for the specified user.

5.5. Using a Bash Script

Lastly, we can use a simple bash script to view the memory usage of every user on our system:

#!/bin/bash

# Initialize the total memory usage variable
total_mem=0     

# Print column headers
printf "%-10s%-10s\n" User MemUsage'(%)'

# Loop through the sorted output of ps and calculate the memory usage per user
while read u m
do
    # Check if we're on a new user and print the total memory usage for the previous user
    [[ $old_user != $u ]] && { printf "%-10s%-0.1f\n" $old_user $total_mem; total_mem=0; }

    # Add the memory usage of the current process to the total memory usage
    total_mem="$(echo $m + $total_mem | bc)"    

    # Save the current user for the next iteration
    old_user=$u

# Read the output of ps, sort it by user, and loop through it
done < <(ps --no-headers -eo user,%mem| sort -k1)    

#EOF

The script uses the ps command to list all processes and their memory usage and sorts the output by the user using the sort command. Then, it loops through the sorted output and calculates the memory usage per user by adding up the memory usage of each process for that user. Finally, the script prints the total memory usage for each user in a user-friendly format.

Now, let’s save the script as check_mem_usage.sh, make it executable with the chmod command, and then execute it:

$ chmod +x memory_usage.sh
$ ./memory_usage.sh

User      MemUsage(%)    
daemon      1.2          
jdoe        6.7          
root        2.9          

As we can see in this sample, our output shows the memory usage for each user, sorted alphabetically by username. In this case, the user jdoe is using the most memory, with the usage of 6.7%.

6. Conclusion

In this article, we’ve discussed how to monitor memory usage per user in Linux using various tools. We started by discussing the basics of memory allocation and management in Linux and the different types of memory and memory hierarchy.

Lastly, we covered the various memory monitoring tools available in Linux. For each tool, we provided a brief overview of how to use it to check memory usage per user, along with sample outputs and explanations.

By using the techniques and tools described in this article, we can gain valuable insights into the usage of memory on our Linux system and take steps to optimize memory usage and improve overall system performance.