Reputation:
Here're what I want to do: I have a library built for 64-bit Linux. Then I created an application linking that library. I want to make sure when I run the application, the memory allocated from the library is always in the higher location (>4GB).
On Windows, user can force allocations to allocate from higher addresses before lower addresses for testing purposes, specify MEM_TOP_DOWN when calling VirtualAlloc or set the following registry value to 0x100000:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference
I wonder if there's similar strategy on Linux. I understand the Linux memory management is different than Window, but I found some clue such as using mmap() or linker scripts. But I haven't been able to achieve the goal. Anybody could provide more information?
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main()
{
void *addr1=0, *addr2=0;
long sz = sysconf(_SC_PAGE_SIZE); // get page size
size_t length = sz*1000*1000; // 1,000,000 pages
int fd = -1;
printf("page size = %ld\n", sz);
// find some available address
int *p = (int*)malloc(sizeof(int));
long start = (long)p + sizeof(int);
free(p); // free it anyway
start += (sz-(start % sz)); // page alignment
printf("start = 0x%lx\n", start);
// mmap fixed
addr1 = mmap((void*)start, length, PROT_NONE,
MAP_PRIVATE|MAP_NORESERVE|MAP_ANONYMOUS|MAP_FIXED, fd, 0);
if (addr1 == MAP_FAILED)
handle_error("mmap");
printf("first map: %tx\n", addr1);
//msync(addr1, length, 0);
// another mmap
addr2 = mmap(NULL, sz*10, PROT_NONE,
MAP_ANONYMOUS|MAP_PRIVATE, fd, 0);
if (addr2 == MAP_FAILED)
handle_error("mmap");
printf("second map: 0x%tx\n", addr2);
// test whether the memory is still available
p = (int*)malloc(sizeof(int)*10);
printf("allocated address: 0x%tx\n", p);
return 0;
}
Output:
page size = 4096
start = 0x1d77000
first map: 1d77000
second map: 0x7f5f26c2f000
allocated address: 0x1d76030
Upvotes: 3
Views: 3333
Reputation: 1
I don't understand why you want to do that (avoiding mmap
giving some address in the first four gigabytes).
Hoever, you could, very early in your program -e.g. start of main
, or even some constructor function- call mmap(2) with MAP_FIXED
and MAP_NORESERVE
on several memory segments to achieve your goal; so you would ensure that all the address space below 4G would be "filled" -either by pre-existing segments of your programs, or by your such calls to mmap
.
However, your library (which could be indirectly dlopen
-ed) could be started much after the program.
Once the first four gigabytes are used in the address spaces, most ordinary mmap
calls (those done by malloc
for example) would go outside.
Of course, you should mmap
at some time before the first malloc
(which would probably call mmap
or sbrk
); and you should take care of the existing memory segments (perhaps you can get them by parsing /proc/self/maps
), because you need to avoid them in your mmap
MAP_FIXED|MAP_NORESERVE
.
And you could also define your own malloc
. Perhaps you could mmap
with MAP_NORESERVE
a huge region (e.g. a terabyte), and have your own malloc
using only address inside (by mmap
-ing again there).
I think you are trying to solve the wrong problem. Doing what I suggest could be tricky... I see no valid reason to avoid addresses in the first 4 Gbytes.
BTW, a good tool to find memory leaks on Linux is valgrind.
Upvotes: 1