emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: When should ralloc.c be used?


From: Daniel Colascione
Subject: Re: When should ralloc.c be used?
Date: Fri, 28 Oct 2016 01:44:33 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0

On 10/28/2016 01:27 AM, Eli Zaretskii wrote:
Cc: address@hidden, address@hidden, address@hidden
From: Daniel Colascione <address@hidden>
Date: Fri, 28 Oct 2016 01:11:08 -0700

Say I mmap (anonymously, for simplicity) a page PROT_NONE. After the
initial mapping, that address space is unavailable for other uses. But
because the page protections are PROT_NONE, my program has no legal
right to access that page, so the OS doesn't have to guarantee that it
can find a physical page to back that page I've mmaped. In this state,
the memory is reserved.

The 20GB PROT_NONE address space reservation itself requires very little
memory. It's just a note in the kernel's VM interval tree that says "the
addresses in range [0x20000, 0x500020000) are reserved". Virtual memory is

Now imagine I change the protections to PROT_READ|PROT_WRITE --- once
the PROT_READ|PROT_WRITE mprotect succeeds, my program has every right
to access that page; under a strict accounting scheme (that is, without
overcommit), the OS has to guarantee that it'll be able to go find a
physical page to back that virtual page. In this state, the memory is
committed -- the kernel has committed to finding backing storage for
that page at some point when the current process tries to access it.

I'm with you up to here.  My question is whether PROT_READ|PROT_WRITE
call could fail after PROT_NONE succeeded.  You seem to say it could;
I thought it couldn't.

Yes, it can fail. This program just failed on my system, which is a strict accounting (echo 2 > /proc/sys/vm/overcommit_memory) Linux box with much less than 100GB total commit available.

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>

size_t GB = (size_t) 1024 * 1024 * 1024;
int
main()
{
    size_t sz = 100*GB;
    void* mem = mmap(NULL, sz, PROT_NONE,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (mem == MAP_FAILED) {
        fprintf(stderr, "map failed: %s\n", strerror(errno));
        return 1;
    }

    if (mprotect(mem, sz, PROT_READ|PROT_WRITE)) {
        fprintf(stderr, "mprotect failed: %s\n", strerror(errno));
        return 1;
    }

    fprintf(stderr, "mprotect worked\n");
    return 0;
}

Say you have a strict-accounting system with 1GB of RAM and 1GB of swap.
I can write a program that reserves 20GB of address space.

I thought such a reservation should fail, because you don't have
enough virtual memory for 20GB of addresses.  IOW, I thought the
ability to reserve address space is restricted by the actual amount of
virtual memory available on the system at the time of the call.  You
seem to say I was wrong.

I'm not sure you're even wrong :-) What does "virtual memory" mean to you? I'm not sure what you have in mind maps to any of the concepts I'm using.

When we allocate memory, we can consume two resources: address space and commit. That 100GB mmap above doesn't consume virtual memory, but it does consume address space. Address space is a finite resource, but usually much larger than commit, which is the sum of RAM and swap space. When you commit a page, the resource you're consuming is commit.

(Technically, the 100GB mapping consumes real memory enough for the OS to remember you've set aside that address space, but it's usually a negligible book-keeping note. On my system, I can make sz equal to 80TB or so before the mmap starts to fail: that's about the size of the address space range dictated by amd64 processor design.)

(In a 32-bit process on modern systems, it's frequently the case that you have more commit on the system than any one process has address space.)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]