Question about os::attempt_reserve_memory_at() on Linux

Thomas Stüfe thomas.stuefe at gmail.com
Tue Apr 28 13:20:20 UTC 2015


Hi all,

I have a question about os::attempt_reserve_memory_at() on Linux:

In the Linux implementation of os::attempt_reserve_memory_at() we have a
fallback implementation which, if the first mmap(req_addr) does not yield
the requested address, repeatedly allocates memory using mmap(NULL) without
freeing it, in the hope that at some point this reserved memory will
intersect with the requested address:

os_linux.cpp:

3708  int i;
3709  for (i = 0; i < max_tries; ++i) {
3710    base[i] = reserve_memory(bytes);
3711
3712    if (base[i] != NULL) {
3713      // Is this the block we wanted?
3714      if (base[i] == requested_addr) {
3715        size[i] = bytes;
3716        break;
3717      }
3718
3719      // Does this overlap the block we wanted? Give back the overlapped
3720      // parts and try again.
3721
3722      ptrdiff_t top_overlap = requested_addr + (bytes + gap) - base[i];
3723      if (top_overlap >= 0 && (size_t)top_overlap < bytes) {
3724        unmap_memory(base[i], top_overlap);
3725        base[i] += top_overlap;
3726        size[i] = bytes - top_overlap;
3727      } else {
3728        ptrdiff_t bottom_overlap = base[i] + bytes - requested_addr;
3729        if (bottom_overlap >= 0 && (size_t)bottom_overlap < bytes) {
3730          unmap_memory(requested_addr, bottom_overlap);
3731          size[i] = bytes - bottom_overlap;
3732        } else {
3733          size[i] = bytes;
3734        }
3735      }
3736    }
3737  }
3738
3739  // Give back the unused reserved pieces.
3740
3741  for (int j = 0; j < i; ++j) {
3742    if (base[j] != NULL) {
3743      unmap_memory(base[j], size[j]);
3744    }
3745  }

It tries by default 10 times.

This code assumes:
1) that the requested address is somewhere in the vicinity of the memory
mmap(NULL) returns by default
2) that the memory returned by mmap(NULL) is monotonously growing

I tested these assumptions using -XX:+UseCompressedOops, because heap
placement for compressed oops is the place which mostly exercises
attempt_reserve_memory_at(). This is especially true since the heap
allocation got more fancy with the introduction of void
ReservedHeapSpace::try_reserve_range() - now we try a lot more attach
points when mapping the heap.

I found that in most of the cases (on a 64bit Linux x64) the first
mmap(req_addr) is already successful - so, we usually get the requested
address we wish for. I guess because the 64bit address space is big, mostly
unpopulated and Linux mmap is very forthcoming.

However, when this did not work (I polluted address space to test the
fallback coding above), I found that fallback never to do anything
reasonable: the allocation addresses of mmap(NULL) returned space would
always be way off the requested addresses requested when allocating the
heap. So it would only end up allocating 10 x size, then give up.

I actually doubt that this fallback coding in
os::attempt_reserve_memory_at() is needed at all - it does is to make
os::attempt_reserve_memory_at() expensive, because it reserves 10 times the
size of the original allocation. Even without committing that memory, this
may get expensive with small pages and large allocation sizes.

So my question is: do we still need this fallback coding? Are there cases
which I am missing? Or could we just remove it?

Best Regards, Thomas


More information about the hotspot-runtime-dev mailing list