Commit 5e3674ca authored by Jonathan Coens's avatar Jonathan Coens Committed by Jordan DeLong

Soft-limit for arenas

Summary: Create an artificial limit on an arena to start throwing bad_alloc before running out of system memory

Test Plan: adjust unit test

Reviewed By: marcelo.juchem@fb.com

FB internal diff: D762695
parent 005a6c1f
...@@ -45,6 +45,13 @@ template <class Alloc> ...@@ -45,6 +45,13 @@ template <class Alloc>
void* Arena<Alloc>::allocateSlow(size_t size) { void* Arena<Alloc>::allocateSlow(size_t size) {
std::pair<Block*, size_t> p; std::pair<Block*, size_t> p;
char* start; char* start;
size_t allocSize = std::max(size, minBlockSize()) + sizeof(Block);
if(sizeLimit_ && allocSize > sizeLimit_ - totalAllocatedSize_) {
throw std::bad_alloc();
}
if (size > minBlockSize()) { if (size > minBlockSize()) {
// Allocate a large block for this chunk only, put it at the back of the // Allocate a large block for this chunk only, put it at the back of the
// list so it doesn't get used for small allocations; don't change ptr_ // list so it doesn't get used for small allocations; don't change ptr_
......
...@@ -60,12 +60,14 @@ template <class Alloc> ...@@ -60,12 +60,14 @@ template <class Alloc>
class Arena { class Arena {
public: public:
explicit Arena(const Alloc& alloc, explicit Arena(const Alloc& alloc,
size_t minBlockSize = kDefaultMinBlockSize) size_t minBlockSize = kDefaultMinBlockSize,
size_t sizeLimit = 0)
: allocAndSize_(alloc, minBlockSize) : allocAndSize_(alloc, minBlockSize)
, ptr_(nullptr) , ptr_(nullptr)
, end_(nullptr) , end_(nullptr)
, totalAllocatedSize_(0) , totalAllocatedSize_(0)
, bytesUsed_(0) { , bytesUsed_(0)
, sizeLimit_(sizeLimit) {
} }
~Arena(); ~Arena();
...@@ -192,6 +194,7 @@ class Arena { ...@@ -192,6 +194,7 @@ class Arena {
char* end_; char* end_;
size_t totalAllocatedSize_; size_t totalAllocatedSize_;
size_t bytesUsed_; size_t bytesUsed_;
size_t sizeLimit_;
}; };
/** /**
...@@ -231,8 +234,10 @@ struct ArenaAllocatorTraits<SysAlloc> { ...@@ -231,8 +234,10 @@ struct ArenaAllocatorTraits<SysAlloc> {
*/ */
class SysArena : public Arena<SysAlloc> { class SysArena : public Arena<SysAlloc> {
public: public:
explicit SysArena(size_t minBlockSize = kDefaultMinBlockSize) explicit SysArena(
: Arena<SysAlloc>(SysAlloc(), minBlockSize) { size_t minBlockSize = kDefaultMinBlockSize,
size_t sizeLimit = 0)
: Arena<SysAlloc>(SysAlloc(), minBlockSize, sizeLimit) {
} }
}; };
......
...@@ -142,6 +142,17 @@ TEST(Arena, Vector) { ...@@ -142,6 +142,17 @@ TEST(Arena, Vector) {
} }
} }
TEST(Arena, SizeLimit) {
static const size_t requestedBlockSize = sizeof(size_t);
static const size_t maxSize = 10 * requestedBlockSize;
SysArena arena(requestedBlockSize, maxSize);
void* a = arena.allocate(sizeof(size_t));
EXPECT_TRUE(a != nullptr);
EXPECT_THROW(arena.allocate(maxSize + 1), std::bad_alloc);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment