Why memory usage is more than physical RAM in Linux? - c

I am working on an embedded system with 512MB of RAM and enough swap memory to support the application. From the kernel, I have restricted the RAM size from the kernel cmd argument to 130MB. And disabled the swap using swapoff -a. I also disabled kernel overcommit, so that the application can run in physical memory alone. I verified the changes from /proc/cmdline and /proc/meminfo. Now when I run the application and check the top values, VSZ for my application is 177m which is more than the actual memory!! How is this possible? Where did this memory came from?

VSZ is virtual memory size which is used by the process. It's normal that it's higher than the size of your physical memory because this is one of the main ideas of this. You should rather look at Resident size (RSS) which is the actual physical memory used by the process.
Look at this example:
I have an nginx process running:
ps -o rss,vsz,cmd ax | grep -i nginx | head -n1
956 31248 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
rss - 956 kB
vsz - 31248 kB
So, it means this process is using 956kB of physical memory, and 31MB of virtual memory.
Disabling swap (swapoff -a), like you did, doesn't disable using virtual memory.
Read about virtual memory here:
Virtual memory

Related

Why program is out of memory when in OS there is still plenty of?

I added some features which require a lot of memory to a C program, it crashes everytime I run it, but it works fine when reduce the memory allocation. Using GDB to debug I find some bizarre results, like assignment would change other pointers, printf doesn't work. I thought this might be memory problem, but using top to monitor memory usage I find there is still plenty of memory.
Finally I used Valgrind to monitor memory, even valgrind ran out of memory:
==3449== Valgrind's memory management: out of memory:
==3449== memcheck:allocate new SecMap's request for 16384 bytes failed.
==3449== 7,625,605,120 bytes have already been mmap-ed ANONYMOUS.
==3449== Valgrind cannot continue. Sorry.
==3449==
==3449== There are several possible reasons for this.
==3449== - You have some kind of memory limit in place. Look at the
==3449== output of 'ulimit -a'. Is there a limit on the size of
==3449== virtual memory or address space?
==3449== - You have run out of swap space.
==3449== - Valgrind has a bug. If you think this is the case or you are
==3449== not sure, please let us know and we'll try to fix it.
==3449== Please note that programs can take substantially more memory than
==3449== normal when running under Valgrind tools, eg. up to twice or
==3449== more, depending on the tool. On a 64-bit machine, Valgrind
==3449== should be able to make use of up 32GB memory. On a 32-bit
==3449== machine, Valgrind should be able to use all the memory available
==3449== to a single process, up to 4GB if that's how you have your
==3449== kernel configured. Most 32-bit Linux setups allow a maximum of
==3449== 3GB per process.
==3449==
==3449== Whatever the reason, Valgrind cannot continue. Sorry.
But using ulimit -a there is no limit on visual space:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 96254
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 96254
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Using top can tell server memory config:
KiB Mem : 24678616 total, 13461572 free, 3457528 used, 7759516 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 20754480 avail Mem
So what reason may caused this result?
update:
OS:
Linux astl09 4.4.0-83-generic #106-Ubuntu SMP Mon Jun 26 17:54:43 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
program is disksim 4.0. I use it on some research.
valgrind:
valgrind-3.11.0

Logic to find heap memory space [duplicate]

I was writing some code and it kept crashing. Later after digging the dumps I realized I was overshooting the maximum heap limit (life would have been easier if I had added a check on malloc). Although I fixed that, is there any way to increase my heap size?
PS: A quite similar question here but the reply is unclear to me.
Heap and memory management is a facility provided by your C library (likely glibc). It maintains the heap and returns chunks of memory to you every time you do a malloc(). It doesn't know heap size limit: every time you request more memory than what is available on the heap, it just goes and asks the kernel for more (either using sbrk() or mmap()).
By default, kernel will almost always give you more memory when asked. This means that malloc() will always return a valid address. It's only when you refer to an allocated page for the first time that the kernel will actually bother to find a page for you. If it finds that it cannot hand you one it runs an OOM killer which according to certain measure called badness (which includes your process's and its children's virtual memory sizes, nice level, overall running time etc) selects a victim and sends it a SIGTERM. This memory management technique is called overcommit and is used by the kernel when /proc/sys/vm/overcommit_memory is 0 or 1. See overcommit-accounting in kernel documentation for details.
By writing 2 into /proc/sys/vm/overcommit_memory you can disable the overcommit. If you do that the kernel will actually check whether it has memory before promising it. This will result in malloc() returning NULL if no more memory is available.
You can also set a limit on the virtual memory a process can allocate with setrlimit() and RLIMIT_AS or with the ulimit -v command. Regardless of the overcommit setting described above, if the process tries to allocate more memory than the limit, kernel will refuse it and malloc() will return NULL. Note than in modern Linux kernel (including entire 2.6.x series) the limit on the resident size (setrlimit() with RLIMIT_RSS or ulimit -m command) is ineffective.
The session below was run on kernel 2.6.32 with 4GB RAM and 8GB swap.
$ cat bigmem.c
#include <stdlib.h>
#include <stdio.h>
int main() {
int i = 0;
for (; i < 13*1024; i++) {
void* p = malloc(1024*1024);
if (p == NULL) {
fprintf(stderr, "malloc() returned NULL on %dth request\n", i);
return 1;
}
}
printf("Allocated it all\n");
return 0;
}
$ cc -o bigmem bigmem.c
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
2
$ ./bigmem
malloc() returned NULL on 8519th request
$ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ ulimit -v $(( 1024*1024 ))
$ ./bigmem
malloc() returned NULL on 1026th request
$
In the example above swapping or OOM kill could never occur, but this would change significantly if the process actually tried to touch all the memory allocated.
To answer your question directly: unless you have virtual memory limit explicitly set with ulimit -v command, there is no heap size limit other than machine's physical resources or logical limit of your address space (relevant in 32-bit systems). Your glibc will keep allocating memory on the heap and will request more and more from the kernel as your heap grows. Eventually you may end up swapping badly if all physical memory is exhausted. Once the swap space is exhausted a random process will be killed by kernel's OOM killer.
Note however, that memory allocation may fail for many more reasons than lack of free memory, fragmentation or reaching a configured limit. The sbrk() and mmap() calls used by glib's allocator have their own failures, e.g. the program break reached another, already allocated address (e.g. shared memory or a page previously mapped with mmap()) or process's maximum number of memory mappings has been exceeded.
The heap usually is as large as the addressable virtual memory on your architecture.
You should check your systems current limits with the ulimit -a command and seek this line max memory size (kbytes, -m) 3008828, this line on my OpenSuse 11.4 x86_64 with ~3.5 GiB of ram says I have roughly 3GB of ram per process.
Then you can truly test your system using this simple program to check max usable memory per process:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[]){
size_t oneHundredMiB=100*1048576;
size_t maxMemMiB=0;
void *memPointer = NULL;
do{
if(memPointer != NULL){
printf("Max Tested Memory = %zi\n",maxMemMiB);
memset(memPointer,0,maxMemMiB);
free(memPointer);
}
maxMemMiB+=oneHundredMiB;
memPointer=malloc(maxMemMiB);
}while(memPointer != NULL);
printf("Max Usable Memory aprox = %zi\n",maxMemMiB-oneHundredMiB);
return 0;
}
This programs gets memory on 100MiB increments, presents the currently allocated memory, allocates 0's on it,then frees the memory. When the system can't give more memory, returns NULL and it displays the final max usable amount of ram.
The Caveat is that your system will start to heavily swap memory in the final stages. Depending on your system configuration, the kernel might decide to kill some processes. I use a 100 MiB increments so there is some breathing space for some apps and the system. You should close anything that you don't want crashing.
That being said. In my system where I'm writing this nothing crashed. And the program above reports barely the same as ulimit -a. The difference is that it actually tested the memory and by means of memset() confirmed the memory was given and used.
For comparison on a Ubuntu 10.04x86 VM with 256 MiB of ram and 400MiB of swap the ulimit report was memory size (kbytes, -m) unlimited and my little program reported 524.288.000 bytes, which is roughly the combined ram and swap, discounting ram used by others software and the kernel.
Edit: As Adam Zalcman wrote, ulimit -m is no longer honored on newer 2.6 and up linux kernels, so i stand corrected. But ulimit -v is honored. For practical results you should replace -m with -v, and look for virtual memory (kbytes, -v) 4515440. It seems mere chance that my suse box had the -m value coinciding with what my little utility reported. You should remember that this is virtual memory assigned by the kernel, if physical ram is insufficient it will take swap space to make up for it.
If you want to know how much physical ram is available without disturbing any process or the system, you can use
long total_available_ram =sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) ;
this will exclude cache and buffer memory, so this number can be far smaller than the actual available memory. OS caches can be quiet large and their eviction can give the needed extra memory, but that is handled by the kernel.
I think your original problem was that malloc failed to allocate the requested memory on your system.
Why this happened is specific to your system.
When a process is loaded, it is allocated memory up to a certain address which is the system break point for the process. Beyond that address the memory is unmapped for the process. So when the process "hits" the "break" point it requests more memory from the system and one way to do this is via the system call sbrk
malloc would do that under the hood but in your system for some reason it failed.
There could be many reasons for this for example:
1) I think in Linux there is a limit for max memory size. I think it is ulimit and perhaps you hit that. Check if it is set to a limit
2) Perhaps your system was too loaded
3) Your program does bad memory management and you end up with fragemented memory so malloc can not get the chunk size you requested.
4) Your program corrupts the malloc internal data structures i.e. bad pointer usage
etc
I'd like to add one point to the previous answers.
Apps have the illusion that malloc() returns 'solid' blocks; in reality, a buffer may exist scattered, pulverized, on many pages of RAM. The crucial fact here is this: the Virtual Memory of a process, containing its code or containing something as a large array, must be contiguous. Let's even admit that code and data be separated; a large array, char str[universe_size], must be contiguous.
Now: can a single app enlarge the heap arbitrarily, to alloc such an array?
The answer could be 'yes' if there were nothing else running in the machine. The heap can be ridiculously huge, but it must have boundaries. At some point, calls to sbrk() (in Linux, the function that, in short, 'enlarges' the heap) should stumble on the area reserved for another application.
This link provides some interesting and clarifying examples, check it out. I did not find the info on Linux.
You can find the process id of your webapp/java process from top.
Use jmap heap - to get the heap allocation. I tested this on AWS-Ec2 for elastic beanstalk and it gives the heap allocated. Here is the detailed answer
Xmx settings in elasticbean stalk through environment properties

Does two different programs load shared library function at same physical memory location

I am using OpenSSL shared library to do simple encryption using AES_cbc_encrypt() function. I want to know if I use this AES_cbc_encrypt() function from two different program, will both program point to the same location in Physical memory for this AES_cbc_encrypt() function?
My other questions are
1 > If I use shared library will it be automatically pointed to same physical memory location by all programs where it is being used ?
Or
2 > Do I need to follow some other technique to force the programs to load the shared library at the same physical memory in RAM. ( I don't think so it is true then there is no use of shared memory concept. It's my understanding).
3 >
How to check whether both program load the shared library function at same physical location.
4> I calculate the location (virtual address) of function in both program by using (& AES_cbc_encrypt) , then using tool capture, I convert this virtual address (VPN) to Physical address (PFN). But, I don't know how to calculate physical address from this VPN, PFN info. So not able to compare further . Any clue ?
For example my virtual address is
=0x400cb0
Virtual address
Starting address- end address
00400000-00402000
Physical Page
: A600000000036E26
: A60000000008A4C3
In my system
**Virtual address space : 48 bit
Physical address space : 36 bit**
I am using GCC under Linux. Any help or pointer/link will be highly appreciated. Thanks in advance.
Read Drepper's paper How To Write Shared Libraries.
Shared libraries use position independent code (to minimize relocation). They are mmap(2)-ed by the dynamic linker ld-linux(8). Linux processes have their address space in virtual memory managed by the linux kernel thru paging.
The kernel will generally share read segments (e.g. the text segment) of shared libraries (so their pages use indeed the same RAM for different processes).
You could use /proc/self/maps (or /proc/1234/maps for the process of pid 1234) to find out the memory mapping of a process. See proc(5).
You should not care about (and application don't directly see) RAM pages. Only the kernel manage physical RAM (and it can move pages in the RAM, page out them to disk, etc.) thru the MMU.
See also mincore(2) & mlock(2). Read also about OOM & thrashing & swap space.
Read Advanced Linux Programming !
While I compile with option -fPIC, I got the same virtual addresses(may be coincidentally) as well as Physical address same for whole library from both program.
gcc -fPIC -o aes openssl_aes.c -lcrypto
This proves that shared library is loaded into same physical location.

How do I allocate a DMA buffer backed by 1GB HugePages in a linux kernel module?

I'm trying to allocate a DMA buffer for a HPC workload. It requires 64GB of buffer space. In between computation, some data is offloaded to a PCIe card. Rather than copy data into a bunch of dinky 4MB buffers given by pci_alloc_consistent, I would like to just create 64 1GB buffers, backed by 1GB HugePages.
Some background info:
kernel version: CentOS 6.4 / 2.6.32-358.el6.x86_64
kernel boot options: hugepagesz=1g hugepages=64 default_hugepagesz=1g
relevant portion of /proc/meminfo:
AnonHugePages: 0 kB
HugePages_Total: 64
HugePages_Free: 64
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 1048576 kB
DirectMap4k: 848 kB
DirectMap2M: 2062336 kB
DirectMap1G: 132120576 kB
I can mount -t hugetlbfs nodev /mnt/hugepages. CONFIG_HUGETLB_PAGE is true. MAP_HUGETLB is defined.
I have read some info on using libhugetlbfs to call get_huge_pages() in user space, but ideally this buffer would be allocated in kernel space. I tried calling do_mmap() with MAP_HUGETLB but it didn't seem to change the number of free hugepages, so I don't think it was actually backing the mmap with huge pages.
So I guess what I'm getting at, is there any way I can map a buffer to a 1GB HugePage in kernel space, or does it have to be done in user space? Or if anyone knows of any other way I can get an immense (1-64GB) amount of contiguous physical memory available as a kernel buffer?
PROBLEM
Normally if you want to allocate a DMA buffer, or get a physical address, this is done in kernel space, as user code should never have to muck around with physical addresses.
Hugetlbfs only provides user-space mappings to allocate 1GB huge pages, and get user-space virtual addresses
No function exists to map a user hugepage virtual address to a physical address
EUREKA
But the function does exist! Buried deep in the 2.6 kernel source code lies this function to get a struct page from a virtual address, marked as "just for testing" and blocked with #if 0:
#if 0 /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
unsigned long start = address;
int length = 1;
int nr;
struct page *page;
struct vm_area_struct *vma;
vma = find_vma(mm, addr);
if (!vma || !is_vm_hugetlb_page(vma))
return ERR_PTR(-EINVAL);
pte = huge_pte_offset(mm, address);
/* hugetlb should be locked, and hence, prefaulted */
WARN_ON(!pte || pte_none(*pte));
page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
WARN_ON(!PageHead(page));
return page;
}
SOLUTION:
Since the function above isn't actually compiled into the kernel, you will need to add it to your driver source.
USER SIDE WORKFLOW
Allocate 1gb hugepages at boot with kernel boot options
Call get_huge_pages() with hugetlbfs to get user space pointer (virtual address)
Pass user virtual address (normal pointer cast to unsigned long) to driver ioctl
KERNEL DRIVER WORKFLOW
Accept user virtual address via ioctl
Call follow_huge_addr to get the struct page*
Call page_to_phys on the struct page* to get the physical address
Provide physical address to device for DMA
Call kmap on the struct page* if you also want a kernel virtual pointer
DISCLAIMER
The above steps are being recollected several years later. I have lost access to the original source code. Do your due diligence and make sure I'm not forgetting a step.
The only reason this works is because 1GB huge pages are allocated at boot time and their physical addresses are permanently locked. Don't try to map a non-1GBhugepage-backed user virtual address into a DMA physical address! You're going to have a bad time!
Test carefully on your system to confirm that your 1GB huge pages are in fact locked in physical memory and that everything is working exactly. This code worked flawlessly on my setup, but there is great danger here if something goes wrong.
This code is only guaranteed to work on x86/x64 architecture (where physical address == bus address), and on kernel version 2.6.XX. There may be an easier way to do this on later kernel versions, or it may be completely impossible now.
This is not commonly done in the kernel space, so not too many examples.
Just like any other page, huge pages are allocated with alloc_pages, to the tune:
struct page *p = alloc_pages(GFP_TRANSHUGE, HPAGE_PMD_ORDER);
HPAGE_PMD_ORDER is a macro, defining an order of a single huge page in terms of normal pages. The above implies that transparent huge pages are enabled in kernel.
Then you can proceed mapping the obtained page pointer in the usual fashion with kmap().
Disclaimer: I never tried it myself, so you may have to do some experimenting around. One thing to check for is this: HPAGE_PMD_SHIFT represents an order of a smaller "huge" page. If you want to use those giant 1GB pages, you will probably need to try a different order, probably PUD_SHIFT - PAGE_SHIFT.
This function returns correct virtual addr in kernel space if given physical address from user space allocated in hugespace.
static inline void * phys_to_virt(unsigned long address)
Look for function on kernel code, it is tested with dpdk and kernel module.

How to check heap size for a process on Linux

I was writing some code and it kept crashing. Later after digging the dumps I realized I was overshooting the maximum heap limit (life would have been easier if I had added a check on malloc). Although I fixed that, is there any way to increase my heap size?
PS: A quite similar question here but the reply is unclear to me.
Heap and memory management is a facility provided by your C library (likely glibc). It maintains the heap and returns chunks of memory to you every time you do a malloc(). It doesn't know heap size limit: every time you request more memory than what is available on the heap, it just goes and asks the kernel for more (either using sbrk() or mmap()).
By default, kernel will almost always give you more memory when asked. This means that malloc() will always return a valid address. It's only when you refer to an allocated page for the first time that the kernel will actually bother to find a page for you. If it finds that it cannot hand you one it runs an OOM killer which according to certain measure called badness (which includes your process's and its children's virtual memory sizes, nice level, overall running time etc) selects a victim and sends it a SIGTERM. This memory management technique is called overcommit and is used by the kernel when /proc/sys/vm/overcommit_memory is 0 or 1. See overcommit-accounting in kernel documentation for details.
By writing 2 into /proc/sys/vm/overcommit_memory you can disable the overcommit. If you do that the kernel will actually check whether it has memory before promising it. This will result in malloc() returning NULL if no more memory is available.
You can also set a limit on the virtual memory a process can allocate with setrlimit() and RLIMIT_AS or with the ulimit -v command. Regardless of the overcommit setting described above, if the process tries to allocate more memory than the limit, kernel will refuse it and malloc() will return NULL. Note than in modern Linux kernel (including entire 2.6.x series) the limit on the resident size (setrlimit() with RLIMIT_RSS or ulimit -m command) is ineffective.
The session below was run on kernel 2.6.32 with 4GB RAM and 8GB swap.
$ cat bigmem.c
#include <stdlib.h>
#include <stdio.h>
int main() {
int i = 0;
for (; i < 13*1024; i++) {
void* p = malloc(1024*1024);
if (p == NULL) {
fprintf(stderr, "malloc() returned NULL on %dth request\n", i);
return 1;
}
}
printf("Allocated it all\n");
return 0;
}
$ cc -o bigmem bigmem.c
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
2
$ ./bigmem
malloc() returned NULL on 8519th request
$ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ ulimit -v $(( 1024*1024 ))
$ ./bigmem
malloc() returned NULL on 1026th request
$
In the example above swapping or OOM kill could never occur, but this would change significantly if the process actually tried to touch all the memory allocated.
To answer your question directly: unless you have virtual memory limit explicitly set with ulimit -v command, there is no heap size limit other than machine's physical resources or logical limit of your address space (relevant in 32-bit systems). Your glibc will keep allocating memory on the heap and will request more and more from the kernel as your heap grows. Eventually you may end up swapping badly if all physical memory is exhausted. Once the swap space is exhausted a random process will be killed by kernel's OOM killer.
Note however, that memory allocation may fail for many more reasons than lack of free memory, fragmentation or reaching a configured limit. The sbrk() and mmap() calls used by glib's allocator have their own failures, e.g. the program break reached another, already allocated address (e.g. shared memory or a page previously mapped with mmap()) or process's maximum number of memory mappings has been exceeded.
The heap usually is as large as the addressable virtual memory on your architecture.
You should check your systems current limits with the ulimit -a command and seek this line max memory size (kbytes, -m) 3008828, this line on my OpenSuse 11.4 x86_64 with ~3.5 GiB of ram says I have roughly 3GB of ram per process.
Then you can truly test your system using this simple program to check max usable memory per process:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[]){
size_t oneHundredMiB=100*1048576;
size_t maxMemMiB=0;
void *memPointer = NULL;
do{
if(memPointer != NULL){
printf("Max Tested Memory = %zi\n",maxMemMiB);
memset(memPointer,0,maxMemMiB);
free(memPointer);
}
maxMemMiB+=oneHundredMiB;
memPointer=malloc(maxMemMiB);
}while(memPointer != NULL);
printf("Max Usable Memory aprox = %zi\n",maxMemMiB-oneHundredMiB);
return 0;
}
This programs gets memory on 100MiB increments, presents the currently allocated memory, allocates 0's on it,then frees the memory. When the system can't give more memory, returns NULL and it displays the final max usable amount of ram.
The Caveat is that your system will start to heavily swap memory in the final stages. Depending on your system configuration, the kernel might decide to kill some processes. I use a 100 MiB increments so there is some breathing space for some apps and the system. You should close anything that you don't want crashing.
That being said. In my system where I'm writing this nothing crashed. And the program above reports barely the same as ulimit -a. The difference is that it actually tested the memory and by means of memset() confirmed the memory was given and used.
For comparison on a Ubuntu 10.04x86 VM with 256 MiB of ram and 400MiB of swap the ulimit report was memory size (kbytes, -m) unlimited and my little program reported 524.288.000 bytes, which is roughly the combined ram and swap, discounting ram used by others software and the kernel.
Edit: As Adam Zalcman wrote, ulimit -m is no longer honored on newer 2.6 and up linux kernels, so i stand corrected. But ulimit -v is honored. For practical results you should replace -m with -v, and look for virtual memory (kbytes, -v) 4515440. It seems mere chance that my suse box had the -m value coinciding with what my little utility reported. You should remember that this is virtual memory assigned by the kernel, if physical ram is insufficient it will take swap space to make up for it.
If you want to know how much physical ram is available without disturbing any process or the system, you can use
long total_available_ram =sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) ;
this will exclude cache and buffer memory, so this number can be far smaller than the actual available memory. OS caches can be quiet large and their eviction can give the needed extra memory, but that is handled by the kernel.
I think your original problem was that malloc failed to allocate the requested memory on your system.
Why this happened is specific to your system.
When a process is loaded, it is allocated memory up to a certain address which is the system break point for the process. Beyond that address the memory is unmapped for the process. So when the process "hits" the "break" point it requests more memory from the system and one way to do this is via the system call sbrk
malloc would do that under the hood but in your system for some reason it failed.
There could be many reasons for this for example:
1) I think in Linux there is a limit for max memory size. I think it is ulimit and perhaps you hit that. Check if it is set to a limit
2) Perhaps your system was too loaded
3) Your program does bad memory management and you end up with fragemented memory so malloc can not get the chunk size you requested.
4) Your program corrupts the malloc internal data structures i.e. bad pointer usage
etc
I'd like to add one point to the previous answers.
Apps have the illusion that malloc() returns 'solid' blocks; in reality, a buffer may exist scattered, pulverized, on many pages of RAM. The crucial fact here is this: the Virtual Memory of a process, containing its code or containing something as a large array, must be contiguous. Let's even admit that code and data be separated; a large array, char str[universe_size], must be contiguous.
Now: can a single app enlarge the heap arbitrarily, to alloc such an array?
The answer could be 'yes' if there were nothing else running in the machine. The heap can be ridiculously huge, but it must have boundaries. At some point, calls to sbrk() (in Linux, the function that, in short, 'enlarges' the heap) should stumble on the area reserved for another application.
This link provides some interesting and clarifying examples, check it out. I did not find the info on Linux.
You can find the process id of your webapp/java process from top.
Use jmap heap - to get the heap allocation. I tested this on AWS-Ec2 for elastic beanstalk and it gives the heap allocated. Here is the detailed answer
Xmx settings in elasticbean stalk through environment properties

Resources