Common/MemArena: Add LazyMemoryRegion to represent a zero-initialized memory region whose pages are only allocated on first access.

This commit is contained in:
Admiral H. Curtiss 2023-09-02 04:01:32 +02:00
parent 5e5887a378
commit 5bd7756064
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
4 changed files with 167 additions and 0 deletions

View File

@ -122,4 +122,42 @@ private:
#endif #endif
}; };
// This class represents a single fixed-size memory region where the individual memory pages are
// only actually allocated on first access. The memory will be zero on first access.
class LazyMemoryRegion final
{
public:
LazyMemoryRegion();
~LazyMemoryRegion();
LazyMemoryRegion(const LazyMemoryRegion&) = delete;
LazyMemoryRegion(LazyMemoryRegion&&) = delete;
LazyMemoryRegion& operator=(const LazyMemoryRegion&) = delete;
LazyMemoryRegion& operator=(LazyMemoryRegion&&) = delete;
///
/// Reserve a memory region.
///
/// @param size The size of the region.
///
/// @return The address the region was mapped at. Returns nullptr on failure.
///
void* Create(size_t size);
///
/// Reset the memory region back to zero, throwing away any mapped pages.
/// This can only be called after a successful call to Create().
///
void Clear();
///
/// Release the memory previously reserved with Create(). After this call the pointer that was
/// returned by Create() will become invalid.
///
void Release();
private:
void* m_memory = nullptr;
size_t m_size = 0;
};
} // namespace Common } // namespace Common

View File

@ -19,6 +19,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include "Common/Assert.h"
#include "Common/CommonFuncs.h" #include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -142,4 +143,46 @@ void MemArena::UnmapFromMemoryRegion(void* view, size_t size)
if (retval == MAP_FAILED) if (retval == MAP_FAILED)
NOTICE_LOG_FMT(MEMMAP, "mmap failed"); NOTICE_LOG_FMT(MEMMAP, "mmap failed");
} }
LazyMemoryRegion::LazyMemoryRegion() = default;
LazyMemoryRegion::~LazyMemoryRegion()
{
Release();
}
void* LazyMemoryRegion::Create(size_t size)
{
ASSERT(!m_memory);
void* memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (!memory)
{
NOTICE_LOG_FMT(MEMMAP, "Memory allocation of {} bytes failed.", size);
return nullptr;
}
m_memory = memory;
m_size = size;
return memory;
}
void LazyMemoryRegion::Clear()
{
ASSERT(m_memory);
mmap(m_memory, m_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
}
void LazyMemoryRegion::Release()
{
if (m_memory)
{
munmap(m_memory, m_size);
m_memory = nullptr;
m_size = 0;
}
}
} // namespace Common } // namespace Common

View File

@ -16,6 +16,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include "Common/Assert.h"
#include "Common/CommonFuncs.h" #include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -108,4 +109,46 @@ void MemArena::UnmapFromMemoryRegion(void* view, size_t size)
if (retval == MAP_FAILED) if (retval == MAP_FAILED)
NOTICE_LOG_FMT(MEMMAP, "mmap failed"); NOTICE_LOG_FMT(MEMMAP, "mmap failed");
} }
LazyMemoryRegion::LazyMemoryRegion() = default;
LazyMemoryRegion::~LazyMemoryRegion()
{
Release();
}
void* LazyMemoryRegion::Create(size_t size)
{
ASSERT(!m_memory);
void* memory = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (!memory)
{
NOTICE_LOG_FMT(MEMMAP, "Memory allocation of {} bytes failed.", size);
return nullptr;
}
m_memory = memory;
m_size = size;
return memory;
}
void LazyMemoryRegion::Clear()
{
ASSERT(m_memory);
mmap(m_memory, m_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
}
void LazyMemoryRegion::Release()
{
if (m_memory)
{
munmap(m_memory, m_size);
m_memory = nullptr;
m_size = 0;
}
}
} // namespace Common } // namespace Common

View File

@ -433,4 +433,47 @@ void MemArena::UnmapFromMemoryRegion(void* view, size_t size)
UnmapViewOfFile(view); UnmapViewOfFile(view);
} }
LazyMemoryRegion::LazyMemoryRegion() = default;
LazyMemoryRegion::~LazyMemoryRegion()
{
Release();
}
void* LazyMemoryRegion::Create(size_t size)
{
ASSERT(!m_memory);
void* memory = VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!memory)
{
NOTICE_LOG_FMT(MEMMAP, "Memory allocation of {} bytes failed.", size);
return nullptr;
}
m_memory = memory;
m_size = size;
return memory;
}
void LazyMemoryRegion::Clear()
{
ASSERT(m_memory);
VirtualFree(m_memory, m_size, MEM_DECOMMIT);
VirtualAlloc(m_memory, m_size, MEM_COMMIT, PAGE_READWRITE);
}
void LazyMemoryRegion::Release()
{
if (m_memory)
{
VirtualFree(m_memory, 0, MEM_RELEASE);
m_memory = nullptr;
m_size = 0;
}
}
} // namespace Common } // namespace Common