IBM Support

Virtual memory and out-of-memory errors on Linux in IBM Integration Bus and IBM App Connect Enterprise

Education


Abstract

In this technote, we will discuss a certain class of out-of-memory errors that are caused by native memory exhaustion that users of IBM Integration Bus or IBM App Connect Enterprise might experience. We will focus our discussion on Linux; however, the concepts are common to almost all modern operating systems, and are not specific to Integration Bus or App Connect Enterprise. We will not discuss out-of-memory errors caused by the Java Virtual Machine running out of heap space, thread stack size, or similar errors.

Content

An introduction to virtual memory

Modern operating systems such as Linux employ a memory management technique called virtual memory or virtual storage, which provides an idealized abstraction over the actual memory resources that are available on the machine. Each process observes its own near-endless virtual memory space in which it can freely allocate pages of memory. The operating system then uses a variety of hardware and software techniques to map these virtual memory pages into physical pages backed by RAM, or on disk by using a page file or swap partition. This removes the burden from program developers to have to manage memory reallocation around the data of other programs, and provides additional security by preventing  processes from seeing each other's memory pages.

One major benefit provided by employing a virtual memory model is that it allows the operating system to allocate more virtual memory pages to programs than it could physically back up by using central storage that uses virtual memory over commitment. This is facilitated by using techniques such as paging unused virtual memory to disk and copy-on-write pages, as well as noting that not all memory pages are generally needed or used by a program at any one time. The cost of this tactic is that expensive paging operations need to occur when an over-committed virtual memory page needs to be backed by physical memory. These techniques are not reserved to operating systems exclusively and are frequently used by hypervisors to allocate more RAM to virtual machines (VMs) and LPARs than is physically available on the host machine.

The two main memory usage stats for a process on Linux are the Resident Set Size (RSS) and the Virtual Memory Size (VSZ). The RSS represents how much memory is allocated to the process and is actively being used in RAM, such as all stack and heap memory; it does not include memory that has been swapped out to disk. The VSZ represents all the virtual memory that the process can access, which includes all memory that is swapped out, memory that has been allocated but not used, and memory that is needed by shared libraries.

Controlling virtual memory on Linux

Linux gives system administrators control over how virtual memory is allocated; for example, the maximum VSZ per process can be controlled by setting a ulimit command or by allowing the administrator to modify or disable the amount of virtual memory overcommitment that it will perform. The rationale for restricting VSZ usage makes sense when you consider that historically a UNIX server was a large shared environment running heterogeneous workloads for many users. In these conditions, it can be desirable for a system administrator to protect other users of the system from rogue applications that might either have a memory leak or consume so much memory that the performance of other processes is degraded. In extreme situations, the applications of other users might even be terminated by an "Out Of Memory (OOM) Killer" process when the physical memory on the system is exhausted.

The Linux kernel has one major setting that controls the behavior of virtual memory overcommitment, vm.overcommit_memory, which takes one of the following three values, as described in the Linux kernel documentation (https://www.kernel.org/doc/Documentation/vm/overcommit-accounting):

 

  • 0 (Heuristic overcommit handling): Obvious overcommits of address space are refused. This value is the default and is used for a typical system.  It ensures that a seriously wild allocation fails while allowing overcommit to reduce swap usage. Root is allowed to allocate slightly more memory in this mode.
  • 1 (Always overcommit): This value is appropriate for some scientific applications. A classic example is code that uses sparse arrays and relies on the virtual memory consisting almost entirely of zero pages.
  • 2 (Don't overcommit): The total address space commit for the system is not permitted to exceed swap + a configurable amount (the default is 50%) of physical RAM. Depending on the amount that you use, in most situations this means that a process will not be terminated while accessing pages, but will receive errors on memory allocation as appropriate. This value is useful for applications that want to guarantee that their memory allocations will be available in the future without having to initialize every page.

Integration servers and virtual memory

The DataFlowEngine process for any given integration server has a large VSZ, even when nothing has been deployed. As an example, I have created a new integration node and integration server that uses the default configuration by using Integration Bus v10.0.0.12 inside our test environment. The RSS consumption of the empty broker is low, about 124MB on this machine, whereas the VSZ is quite large, consuming nearly 3.8 GB of virtual memory. This is due to the large number of libraries that the product is built on, and other components that we embed that allocate large chunks of memory, such as the JVM heap, byte code cache, and the Node.js run time. This space is often pre-allocated to avoid runtime performance issues that are associated with up-sizing a contiguous memory block or because there are requirements for certain types of memory to be allocated in lower addresses (for example, the JVM requires thread stacks to be allocated under the 4GB address line mark).  It is important to note that depending on your workload, large portions of the VSZ might never actually be used.

For typical Integration Bus workloads, a system is usually running in a largely unattended capacity with a well-defined workload. Often, an Integration Bus server will, by using virtualization, be given its own virtual server, container, or LPAR. Under these conditions, it makes less sense to restrict Integration Bus or IBM MQ's use of virtual memory. Instead, we would usually recommend that the system is sized appropriately based on the expected workload, which in turn is based on performance test measurements, and then all limits on VSZ are removed.
 
If the total RSS that is used by the workload is greater than the physical memory available on the system, processes will still be terminated by the OOM killer, and workloads will fail due to memory contention.  Therefore, in combination with the recommendation to permit Integration Bus and MQ processes unlimited VSZ access, it is important to ensure that you have adequate monitoring at the system level.

Customers will often monitor the available free memory and issue alerts at specific thresholds. This can provide a system administrator a way to take manual or scripted action to cope with processes that are in danger of causing memory contention (although the risk of this happening should have been mitigated in the performance testing phase).

Out-of-memory errors and vm.overcommit_memory

Out-of-memory errors might occur inside an integration server despite the fact that there is plenty of available physical RAM on the system. One common symptom of this is a Java core file being produced that states:

1TISIGINFO Dump Event "systhrow" (00040000) Detail "java/lang/OutOfMemoryError" "Failed to create a thread: retVal -1073741830, errno 11" received

where the abending thread is inside java.lang.Thread.startImpl:

3XMTHREADINFO3 Java callstack:
4XESTACKTRACE at java/lang/Thread.startImpl(Native Method)
4XESTACKTRACE at java/lang/Thread.start(Thread.java:981)

Other symptoms include syslog entries from the ODBC drivers that state that a native memory allocation failed, such as:

BIP2322E: Database error: SQL State 'HY001'; Native Error Code '-99999'; Error Text '[unixODBC][IBM][CLI Driver] CLI0120E Memory allocation failure. SQLSTATE=HY001'.

These errors indicate that the system has virtual memory overcommit disabled by having set vm.overcommit_memory to 2. As discussed above, an integration server requires the ability to overcommit on memory in a wide range of situations. We recommend that users set vm.overcommit_memory to the default value of zero (0) to prevent or resolve these kinds of errors.

 

[{"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Product":{"code":"SSNQK6","label":"IBM Integration Bus"},"Component":"","Platform":[{"code":"PF016","label":"Linux"}],"Version":"All Versions","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}}]

Document Information

Modified date:
23 March 2020

UID

ibm10734131