Be aware that the address space size for "64bit operating systems" is not necessarily covering the full 64bit range.
On x64 (64bit x86, aka 'AMD64'), for example, the actual available virtual address range is "only" 2x128TB, i.e. 48bit in two disjoint 47bit chunks. On some SPARC systems, it's 2x2TB, or 2x8TB (41/44 bits). This is due to the way the MMU works on these platforms.
In addition to these architectural limitations, the way the operating system lays out your address spaces also plays a role here.
64bit Windows on x64, for example, limits the virtual address size of an (even 64bit) application to 8TB (each kernel and user side1).
On UN*X systems (including Linux, MacOSX and the *BSDs), there is RLIMIT_AS
that one can query for via getrlimit()
, and - within system-specific limits - adjust via setrlimit
. The ulimit
command uses those. They return/set the upper bound, though, i.e. the allowed total virtual address space, including all mappings that a process can create (via mmap()
or the malloc
backend, sbrk()
).
But the total address space size is different from the maximum size of a single mapping ...
Given this, it's not that hard to exhaust the virtual address space even on 64bit Linux; just try, for a test, to mmap()
the same 500GB file, say, two hundred times. The mmap will fail, eventually.
In short:
mmap()
will definitely fail once you're out of virtual address space. Which is, somewhat surprisingly, achievable on many "64bit" architectures simply because virtual addresses might have less than 64 significant bits. The exact cutoff depends on your CPU and your operating system, and an upper bound can be queried via getrlimit(RLIMIT_AS)
or set via setrlimit(RLIMIT_AS)
.
- Address space fragmentation can occur on 64bit by frequently using
mmap()
/ munmap()
in different orders and with different-sized blocks. This will ultimately limit the maximum size you'll be able to map as a single chunk. Predicting when exactly this will happen is hard since it both depends on your "mapping history" and the operating systems' virtual address space allocation algorithm. If ASLR (address space layout randomization) is done by the OS, it might be unpredictable in detail, and not exactly reproducible.
malloc()
will also fail no later than reaching the total VA limit, on systems (like Linux) where overcommit allows you to "ask" for more memory than there is in the system (physical + swap).
- On machines / operating systems where no overcommit is enabled, both
malloc()
and mmap()
with MAP_ANON
and/or MAP_PRIVATE
will fail when physical + swap is exhausted, because these types of mappings require backing store by actual memory or swap.
Little technical update: Like x86 and sparc mentioned above, the new ARMv8 (64bit ARM, called "AArch64" in Linux) MMU also has a "split" address space / an address space hole - out of the 64 bits in an address, only 40 are relevant. Linux gives 39bit for user, virtual addresses 0 ...
onwards, 39bit for kernel, virtual addresses ... 0xFFFFFFFF.FFFFFFFF
, so the limit there is 512GB (minus what's in use already at the time the app tries the mmap
).
See comments here (from the AArch64 architecture enabler kernel patch series).