Implement PAL backoff (#227)

The POSIX PAL and in some configurations the Windows PAL overallocate
address space. If address space has become exhausted then this can lead
to issues, where the PAL fails, even though there is enough aligned
address space to satisfy the underlying request.

This commit tries increasingly smaller overallocation sizes in an
attempt to succeed in more cases.
This commit is contained in:
Matthew Parkinson
2020-07-08 16:17:33 +01:00
committed by GitHub
parent c6197cb5f2
commit 591b049585
2 changed files with 30 additions and 18 deletions

View File

@@ -209,23 +209,30 @@ namespace snmalloc
*/
std::pair<void*, size_t> reserve_at_least(size_t size) noexcept
{
SNMALLOC_ASSERT(size == bits::next_pow2(size));
// Magic number for over-allocating chosen by the Pal
// These should be further refined based on experiments.
constexpr size_t min_size =
bits::is64() ? bits::one_at_bit(32) : bits::one_at_bit(28);
auto size_request = bits::max(size, min_size);
void* p = mmap(
nullptr,
size_request,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | DefaultMMAPFlags<OS>::flags,
AnonFD<OS>::fd,
0);
if (p == MAP_FAILED)
OS::error("Out of memory");
for (size_t size_request = bits::max(size, min_size);
size_request >= size;
size_request = size_request / 2)
{
void* p = mmap(
nullptr,
size_request,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | DefaultMMAPFlags<OS>::flags,
AnonFD<OS>::fd,
0);
return {p, size_request};
if (p != MAP_FAILED)
return {p, size_request};
}
OS::error("Out of memory");
}
};
} // namespace snmalloc

View File

@@ -218,19 +218,24 @@ namespace snmalloc
# else
std::pair<void*, size_t> reserve_at_least(size_t size) noexcept
{
SNMALLOC_ASSERT(size == bits::next_pow2(size));
// Magic number for over-allocating chosen by the Pal
// These should be further refined based on experiments.
constexpr size_t min_size =
bits::is64() ? bits::one_at_bit(32) : bits::one_at_bit(28);
auto size_request = bits::max(size, min_size);
DWORD flags = MEM_RESERVE;
void* ret = VirtualAlloc(nullptr, size_request, flags, PAGE_READWRITE);
if (ret == nullptr)
for (size_t size_request = bits::max(size, min_size);
size_request >= size;
size_request = size_request / 2)
{
error("Failed to allocate memory\n");
void* ret =
VirtualAlloc(nullptr, size_request, MEM_RESERVE, PAGE_READWRITE);
if (ret != nullptr)
{
return std::pair(ret, size_request);
}
}
return std::pair(ret, size_request);
error("Failed to allocate memory\n");
}
# endif
};