I have a call to mmap() which I try to map 64MB using MAP_ANONYMOUS as follows:
void *block = mmap(0, 67108864, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (block == MAP_FAILED)
exit(1);
I understand that to actually own the memory, I need to hit that block of memory. I want to add some sort of 0's or empty strings to actually own the memory. How would I do that? I tried the following, but that obviously segfaults (I know why it does):
char *temp = block;
for (int i = 0; i < 67108864; i++) {
*temp = '0';
temp++;
}
How would I actually gain ownership of that block by assigning something in that block?
Thanks!
Your process already owns the memory, but what I think you want is to make it resident. That is, you want the kernel to allocate physical memory for the mmaped region.
The kernel allocates a virtual memory area (VMA) for the process, but this just specifies a valid region and doesn't actually allocate physical pages (or frames as they are also sometimes called). To make the kernel allocate entries in the page table, all you need to do is force a page fault.
The easiest way to force a page fault is to touch the memory just like you're doing. Though, because your page size is almost certainly 4096 bytes, you really only need to read one byte every 4096 bytes thereby reducing the amount of work you actually need to do.
Finally, because you are setting the pages PROT_READ, you will actually want to read from each page rather than try to write.
Your question is not very well formulated. I don't understand why you think the process is not owning its memory obtained thru mmap?
Your newly mmap-ed memory zone has only PROT_READ (so you can just read the zeros inside) and you need that to be PROT_READ|PROT_WRITE to be able to write inside.
But your process already "owns" the memory once the mmap returned.
If the process has pid 1234, you could sequentially read (perhaps with cat /proc/1234/maps in a different terminal) its memory map thru /proc/1234/maps; from inside your process, use /proc/self/maps.
Maybe you are interested in memory overcommit; there is a way to disable that.
Perhaps the mincore(2), msync(2), mlock(2) syscalls are interesting you.
Maybe you want the MAP_POPULATE or MAP_LOCKED flag of mmap(2)
I actually don't understand why you say "own the memory" in your question, which I don't understand very well. If you just want to disable memory overcommit, please tell.
And you might also mmap some file segment. I believe there is no possible overcommit in that case. But I would just suggest to disable memory overcommit in your entire system, thru /proc/sys/vm/overcommit_memory.
Related
I am currently editing a program I inherited to be able to work with 23 GB files. As such, to maintain low memory, I am using mmap to load arrays which I had created in a previous program. However, I load these arrays, and then enter into a function and the shared and reserved memory spikes, even though I do not believe I ever allocate anything. When running, the memory starts at 0 and then quickly increases to 90% (~36GB as I have 40GB of ram) and stays there. Eventually, I start needing memory (less than 30GB) and the program then gets killed.
Usually, I would suspect that this issue would be due to allocation, or that I was somehow allocating memory. However, I am not allocating any memory (although I am reading in mmaped files).
The curious thing is that the memory reserved is equal to the amount of memory shared (see attached screenshot).
The functions that I wrote to access mmaped arrays:
double* loadArrayDouble(ssize_t size, char* backupFile, int *filedestination) {
*filedestination = open(backupFile, O_RDWR | O_CREAT, 0644);
if (*filedestination < 0) {
perror("open failed");
exit(1);
}
// make sure file is big enough
if (lseek(*filedestination,size*sizeof(double), SEEK_SET) == -1) {
perror("seek to len failed");
exit(1);
}
if (lseek(*filedestination, 0, SEEK_SET) == -1) {
perror("seek to 0 failed");
exit(1);
}
double *array1 = mmap(NULL, size*sizeof(double), PROT_READ | PROT_WRITE, MAP_SHARED, *filedestination, 0);
if (array1 == MAP_FAILED) {
perror("mmap failed");
exit(1);
}
return array1;
}
Please let me know if there is any other code to include.. It appears that the memory increases significantly even though double* file1 = loadArrayDouble(SeqSize, "/home/HonoredTarget/file1", &fileIT); is called multiple times (for each of the 6 arrays)
"Res" is short for "resident", not "reserved". Resident memory refers to the process memory which the kernel happens to have resident at the moment; the virtual memory system might drop a resident page at any moment, so it's not in any way a limitation. However, the kernel attempts not to swap out pages which seem to be active. The OOM killer will act if your process is churning too many pages in and out of memory. If you use data sequentially, then it usually doesn't matter how much you have mmap'ed, because only the recent pages will be resident. But if you skip around in the memory, reading a bit here and writing a bit there, then you'll create more churn. That seems like what is happening.
"shr" (shared) memory does in fact refer to memory which could be shared with another process (whether or not it actually is shared with another process). The fact that you use MAP_SHARED means that it is not surprising that all of your mmap'ed pages are shared. You need MAP_SHARED if your program modifies the data in the file, which I guess it does.
The "virt" (virtual) column measures how much of your address spaced you've actually mapped (including memory mapped to anonymous backing storage by whatever dynamic allocation library you're using.) 170G seems a bit high to me. If you have six 23GB files mapped simultaneously, that would be 138GB. But perhaps those numbers were just estimates. Anyway, it doesn't matter that much, as long as you're within the virtual memory limits you've set. (Although page tables do occupy real memory, so there is some effect.)
Memory mapping does not save you memory, really. When you mmap a file, the contents of the file still need to be read into memory in order for your program to use the data. The big advantage to mmap is that you don't have to futz around with allocating buffers and issuing read calls. Also, there is no need to copy data from the kernel buffer into which the file is read. So it can be a lot easier and more efficient, but not always; it depends a lot on the precise access pattern.
One thing to note: the following snippet does not do what the comment says it does:
// make sure file is big enough
if (lseek(*filedestination,size*sizeof(double), SEEK_SET) == -1) {
perror("seek to len failed");
exit(1);
}
lseek only sets the file position for the next read or write operation. If the file does not extend to that point, you'll get an EOF indication when you read, or the file will be extended (sparsely) if you write. So there's really not much point. If you want to check the file size, use stat. Or make sure you read at least one byte after doing the seek.
There's also not a lot of point using O_CREAT in the open call, since if the file doesn't exist and thus gets created, it will have size 0, which is presumably an error. Leaving O_CREAT off means the open call will fail if the file doesn't exist, which is likely what you want.
Finally, if you are not actually modifying the file contents, don't mmap with PROT_WRITE. PROT_READ pages are a lot easier for the kernel to deal with, because they can just be dropped and read back in later. (For writable pages, the kernel keeps track of the fact that the page has been modified, but if you aren't planning on writing and you don't allow modification, that makes the kernel's task a bit easier.)
Since you are (apparently) getting your process killed by the OOM killer, even though the memory you are using is MAP_SHARED (so never requires backing store -- it is auotmatically backed by the file), it would appear you are running your linux with no swap space, which is a bad idea if you have large mapped files like this, as it will cause processes to get killed whenever your resident memory approaches your physical memory. So the obvious solution would be to add a swap file -- even a small amount (1-2GB) will avoid the OOM killer problem. There are lots of tutorials online about how to add a swapfile in linux. You can look here or here or search for yourself.
If for some reason you don't want to add a swapfile, you may be able to reduce the frequency of getting killed by increasing the "swappiness" of your system -- this will cause the kernel to drop pages of your mmapped files more readily, thus reducing the likelyhood of getting into an OOM situation. You do this by increasing the vm.swappiness parameter either in your sysctl.conf file (for bootup) or by writing a new value to your /proc/sys/vm/swappiness file.
I'm making a game where the world is divided into chunks of data describing the world. I keep the chunks in a dynamically allocated array so I have to use malloc() when initializing the world's data structures.
Reading the malloc() man page, there is a Note as follows:
By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee
that the memory really is available. In case it turns out that the
system is out of memory, one or more processes will be killed by the
OOM killer. For more information, see the description of
/proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file
Documentation/vm/overcommit-accounting.
If Linux is set to use optimistic memory allocation then does this mean it doesn't always return the full amount of memory I requested in the call to malloc()?
I read that optimistic memory allocation an be disabled by modifying the kernel, but I don't want to do that.
So is there a way to check whether the program has allocated the requested amount?
This is not something you need to deal with from an application perspective. Users who don't want random processes killed by the "OOM killer" will disable overcommit themselves via
echo "2" > /proc/sys/vm/overcommit_memory
This is their choice, not yours.
But from another standpoint, it doesn't matter. Typical "recommended" amounts of swap are so ridiculous that no reasonable amount of malloc is going to fail to have physical storage to back it. However, you could easily allocate so much (even with forced MAP_POPULATE or manually touching it all) to keep the system thrashing swap for hours/days/weeks. There is no canonical way to ask the system to notify you and give an error if the amount of memory you want is going to bog down the system swapping.
The whole situation is a mess, but as an application developer, your role in the fix is just to use malloc correctly and check for a null return value. The rest of the responsibility is on distributions and the kernel maintainers.
Instead of malloc you can allocate the necessary memory directly by mmap, with MAP_POPULATE that advises the kernel to map the pages immediately.
#include <sys/mman.h>
// allocate length bytes and prefault the memory so
// that it surely is mapped
void *block = mmap(NULL, length, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE,
-1, 0);
// free the block allocated previously
// note, you need to know the size
munmap(block, length);
But the better alternative is that usually the world is saved to a file, so you would mmap the contents directly from a file:
int fd = open('world.bin', 'r+');
void *block = mmap(NULL, <filesize>, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
The file world.bin is mapped into the memory starting from address block; all changes to the memory would also written transparently to the file - no need to worry if there is enough RAM as linux will take care of mapping the pages in and out automatically.
Do note that some of these flags are not defined unless you have a certain feature test macro defined:
Certain flags constants are defined only if either _BSD_SOURCE or
_SVID_SOURCE is defined. (Requiring _GNU_SOURCE also suffices, and requiring that macro specifically would have been more logical, since
these flags are all Linux-specific.) The relevant flags are:
MAP_32BIT, MAP_ANONYMOUS (and the synonym MAP_ANON),
MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB,
MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE, and MAP_STACK.
I read that when you try to allocate more bytes than are available in RAM using malloc(), it allocates virtual memory. At least on Linux.
I want to allocate a huge amount of virtual memory, lets say 100 GB. So, I wrote something like this:
void* virtual_memory = malloc(100 gb int);
But the returned pointer is NULL.
I execute this code on a 64-bit Ubuntu virtual machine.
What am I doing wrong?
EDIT
What I'm trying to achieve is to make htop tool displaying 100GB in VIRT column for my process.
UPDATE
I CAN call malloc to allocate 2 GB at once 50 times
I read that when you try to allocate more bytes than are available in RAM using malloc(), it allocates virtual memory
To start with, this is not correct. You always allocate virtual memory. This virtual memory is mapped to some area on the Physical memory(RAM) or the swap space. If the swap space + physical memory is less than 100 GBs, your allocation will fail. Also, the libc implementation might fail to allocate such a large amount, if it has some (programmable) limit set.
but I have a strange task to show up 100gb of virtual memory for the process in htop tool. And it's claimed to be achievable via single line of code.
Yes if you just need this much virtual memory, you can reserve memory but not commit it. You can read upon how mmap(*NIX) or VirtualAlloc(Windows) can be used for the same.
When you reserve a particular Virtual Address range, you tell the operating system that you intend to use this range, so other code can't use that. But it doesn't mean you can actually use it. This also means that it doesn't need a RAM/Swap backing. So you will be able to reserve arbitrarily large amount (less than 2^48 bytes on your 64 bit system of course).
Although I am not sure if htop will include that in the value it shows, you will have to try that out.
If this doesn't indeed add to your virtual memory count, you can map it to a file, instead of mapping it anonymously. This might create a 100 GB file on your system (assuming you have that much space), but you should even be able to read/write to it.
Following code can be used on linux -
int fd = open("temp.txt", O_RDWR | O_CREAT);
void* addr = mmap(NULL, 100 * GBS, PROT_WRITE | PROT_READ, MAP_PRIVATE, fd, 0);
The following code done the thing for me:
for (int i = 0; i < 50; ++i) {
malloc(int_pow(2, 31));
}
Where int_pow is just a custom pow implementation, which operates integers. After running this app htop tool shows that it uses exactly 100GB of virtual memory.
I am writing a program to leak memory( main memory ) to test how the system behaves with low system memory and swap memory. We are using the following loop which runs periodically and leaks memory
main(int argc, char* argv[] )
{
int arg_mem = argv[1];
while(1)
{
u_int_ptr =(unsigned int*) malloc(arg_mem * 1024 * 1024);
if( u_int_ptr == NULL )
printf("\n leakyapp Daemon FAILED due to insufficient available memory....");
sleep( arg_time );
}
}
Above loop runs for sometime and prints the message "leakyapp Daemon FAILED due to insufficient available memory...." . But when I run the command "free" I can see that running this program has no effect either on Main memory or Swap.
Am I doing something wrong ?
Physical memory is not committed to your allocations until you actually write into it.
If you have a kernel version after 2.6.23, use mmap() with the MAP_POPULATE flag instead of malloc():
u_int_ptr = mmap(NULL, arg_mem * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0);
if (u_int_ptr == MAP_FAILED)
/* ... */
If you have an older kernel, you'll have to touch each page in the allocation.
There might be some sort of copy-on-write optimization. I would suggest actually writing something to the memory you are allocating.
What is happening is that malloc requests argmem * 256 pages from the heap (assuming a 4 Kbyte page size). The heap in turn requests the memory from the operating system. However, all that does is create entries in the page table for the newly allocated memory block. No actual physical RAM is allocated to the process, except that required by the heap to track the malloc request.
As soon as the process tries to access one of those pages by reading or writing, a page fault is generated because the entry in the page table is effectively a dangling pointer. The operating system will then allocate a physical page to the process. It's only then that you'll see the available physical memory go down.
Since all new pages start completely zeroed out, Linux might employ a "copy on write" strategy to optimise page allocation. i.e. it might keep a single page totally zeroed and always allocate that one when a process tries to read from a previously unused page. Only when the process tries to write to that new page would it actually allocate a completely fresh page from physical RAM. I don't know if Linux actually does this, but if it does, merely reading from a new page is not going to be enough to increase physical memory usage.
So, your best strategy is to allocate your large block of RAM and then write something at 4096 byte intervals throughout it.
What does ulimit -m -v print?
Explanation: On any server OS, you can limit the amount of resources a process can allocate to make sure that a single runaway process can't bring down the whole machine.
I'm guessing (based on the command line argument) that you're using a desktop/server OS and not an embedded system.
Allocating memory like this is probably not consuming much RAM. Your memory allocation might not have even succeeded - on some OSs (e.g. Linux), malloc() can return non-NULL even when you ask for more memory than is available.
Without knowing what your OS is and exactly what you're trying to test, it's difficult to suggest anything specific, but you might want to look at more low level ways of allocating memory than malloc(), or ways of controlling the virtual memory system. On Linux you might want to look at mlock().
I think caf already explained it. Linux is usually configured to allow overcommitting memory. You allocate huge chunks of memory, but internally there happens nothing but just making a note that you process wants this huge chunk of memory. It's not before you try to write that chunk, that the kernel tries to find free virtual memory to satisfy the read/write access. This is a bit like flight booking: Airlines usually overbook the flights, because there's always a percentage of passengers who do not show up.
You can force the memory to be committed by writing to the chunk with memset() after allocation. calloc should work too.
Does protection flag affect the sharing between processes? If I have PROT_READ|PROT_WRITE -protected mmapped memory region, is it still fully shared as long as I haven't written into it?
int prot = PROT_READ|PROT_EXEC;
image = mmap(NULL, filesize, prot, MAP_PRIVATE, fildes, 0);
vs:
int prot = PROT_READ|PROT_WRITE|PROT_EXEC;
image = mmap(...)
I'd want to make small modification to small portion of the memory region after I've mapped it, then re-mprotect it all, because it's simpler than mprotecting small portions when I need to do so.
The question is whether it ends up forcing the whole file copied per process or just the portions I modified per process?
According to the mmap(2) man page on a recent Linux system, MAP_PRIVATE allocates the memory using copy-on-write (COW). This means, your memory will not be duplicated unless you make changes to it. As COW is an efficient method to implement this, I assume it is also done this way in other *NIX systems.
The memory for mmap is organized in equal-sized chunks, so called pages. Memory will always be mapped in multiples of the page size, i.e. whole pages. Each page can be swapped independently. So if you write something to this mmap'ed memory range, only at least one page has to be copied.
The page size depends on your system, on x86 it is usually 4096 bytes. If you are interested in the page size of your system, you can use sysconf(3).
#include <unistd.h>
long pagesize = sysconf(_SC_PAGESIZE);
The pointer you get from mmap() will already point to a multiple of the page size and you should pass mprotect() an address being aligned to a page boundary.