GC: change collection trigger (#108)
This commit is contained in:
parent
3366aae6f2
commit
e313e58ea3
@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
namespace effil {
|
namespace effil {
|
||||||
|
|
||||||
|
constexpr size_t MINIMUN_SIZE_LEFT = 100;
|
||||||
|
|
||||||
GC::GC()
|
GC::GC()
|
||||||
: enabled_(true)
|
: enabled_(true)
|
||||||
, lastCleanup_(0)
|
, lastCleanup_(MINIMUN_SIZE_LEFT)
|
||||||
, step_(200) {}
|
, step_(2.) {}
|
||||||
|
|
||||||
// Here is the naive tri-color marking
|
// Here is the naive tri-color marking
|
||||||
// garbage collecting algorithm implementation.
|
// garbage collecting algorithm implementation.
|
||||||
@ -41,7 +43,7 @@ void GC::collect() {
|
|||||||
DEBUG << "Removing " << (objects_.size() - black.size()) << " out of " << objects_.size() << std::endl;
|
DEBUG << "Removing " << (objects_.size() - black.size()) << " out of " << objects_.size() << std::endl;
|
||||||
objects_ = std::move(black);
|
objects_ = std::move(black);
|
||||||
|
|
||||||
lastCleanup_.store(0);
|
lastCleanup_.store(std::max(objects_.size(), MINIMUN_SIZE_LEFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GC::count() const {
|
size_t GC::count() const {
|
||||||
@ -63,9 +65,13 @@ sol::table GC::exportAPI(sol::state_view& lua) {
|
|||||||
api["step"] = [](const sol::stack_object& newStep){
|
api["step"] = [](const sol::stack_object& newStep){
|
||||||
auto previous = instance().step();
|
auto previous = instance().step();
|
||||||
if (newStep.valid()) {
|
if (newStep.valid()) {
|
||||||
REQUIRE(newStep.get_type() == sol::type::number) << "bad argument #1 to 'effil.gc.step' (number expected, got " << luaTypename(newStep) << ")";
|
REQUIRE(newStep.get_type() == sol::type::number)
|
||||||
REQUIRE(newStep.as<int>() >= 0) << "effil.gc.step: invalid capacity value = " << newStep.as<int>();
|
<< "bad argument #1 to 'effil.gc.step' (number expected, got "
|
||||||
instance().step(newStep.as<size_t>());
|
<< luaTypename(newStep) << ")";
|
||||||
|
REQUIRE(newStep.as<double>() > 1)
|
||||||
|
<< "effil.gc.step: invalid capacity value = "
|
||||||
|
<< newStep.as<double>();
|
||||||
|
instance().step(newStep.as<double>());
|
||||||
}
|
}
|
||||||
return previous;
|
return previous;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,8 +17,8 @@ public:
|
|||||||
// This method is used to create all managed objects.
|
// This method is used to create all managed objects.
|
||||||
template <typename ViewType, typename... Args>
|
template <typename ViewType, typename... Args>
|
||||||
ViewType create(Args&&... args) {
|
ViewType create(Args&&... args) {
|
||||||
if (enabled_ && lastCleanup_.fetch_add(1) == step_)
|
if (enabled_ && count() >= step_ * lastCleanup_)
|
||||||
collect();
|
collect();
|
||||||
|
|
||||||
std::unique_ptr<ViewType> object(new ViewType(std::forward<Args>(args)...));
|
std::unique_ptr<ViewType> object(new ViewType(std::forward<Args>(args)...));
|
||||||
auto copy = *object;
|
auto copy = *object;
|
||||||
@ -43,8 +43,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
mutable std::mutex lock_;
|
mutable std::mutex lock_;
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
std::atomic<size_t> lastCleanup_;
|
std::atomic<uint64_t> lastCleanup_;
|
||||||
size_t step_;
|
double step_;
|
||||||
std::unordered_map<GCHandle, std::unique_ptr<BaseGCObject>> objects_;
|
std::unordered_map<GCHandle, std::unique_ptr<BaseGCObject>> objects_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -55,8 +55,8 @@ private:
|
|||||||
void collect();
|
void collect();
|
||||||
void pause() { enabled_ = false; }
|
void pause() { enabled_ = false; }
|
||||||
void resume() { enabled_ = true; }
|
void resume() { enabled_ = true; }
|
||||||
size_t step() const { return step_; }
|
double step() const { return step_; }
|
||||||
void step(size_t newStep) { step_ = newStep; }
|
void step(double newStep) { step_ = newStep; }
|
||||||
bool enabled() { return enabled_; }
|
bool enabled() { return enabled_; }
|
||||||
size_t count() const;
|
size_t count() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,3 +55,67 @@ test.gc.store_same_value = function()
|
|||||||
effil.gc.collect()
|
effil.gc.collect()
|
||||||
c:pop()[1] = 0
|
c:pop()[1] = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function create_fabric()
|
||||||
|
local f = { data = {} }
|
||||||
|
|
||||||
|
function f:create(num)
|
||||||
|
for i = 1, num do
|
||||||
|
table.insert(self.data, effil.table())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function f:remove(num)
|
||||||
|
for i = 1, num do
|
||||||
|
table.remove(self.data, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
test.gc.check_iterative = function()
|
||||||
|
test.equal(gc.count(), 1)
|
||||||
|
local fabric = create_fabric()
|
||||||
|
test.equal(2, effil.gc.step())
|
||||||
|
|
||||||
|
fabric:create(199)
|
||||||
|
test.equal(gc.count(), 200)
|
||||||
|
|
||||||
|
fabric:remove(50)
|
||||||
|
collectgarbage()
|
||||||
|
test.equal(gc.count(), 200)
|
||||||
|
|
||||||
|
fabric:create(1) -- trigger GC
|
||||||
|
test.equal(gc.count(), 151)
|
||||||
|
fabric:remove(150)
|
||||||
|
|
||||||
|
fabric:create(149)
|
||||||
|
test.equal(gc.count(), 300)
|
||||||
|
collectgarbage()
|
||||||
|
|
||||||
|
fabric:create(1) -- trigger GC
|
||||||
|
test.equal(gc.count(), 151)
|
||||||
|
end
|
||||||
|
|
||||||
|
test.gc.check_step = function()
|
||||||
|
local fabric = create_fabric()
|
||||||
|
effil.gc.step(3)
|
||||||
|
|
||||||
|
fabric:create(299)
|
||||||
|
fabric:remove(100)
|
||||||
|
test.equal(gc.count(), 300)
|
||||||
|
collectgarbage()
|
||||||
|
|
||||||
|
fabric:create(1) -- trigger GC
|
||||||
|
test.equal(gc.count(), 201)
|
||||||
|
|
||||||
|
test.equal(3, effil.gc.step(2.5))
|
||||||
|
|
||||||
|
fabric:create(299)
|
||||||
|
fabric:remove(250)
|
||||||
|
test.equal(gc.count(), 500)
|
||||||
|
collectgarbage()
|
||||||
|
|
||||||
|
fabric:create(1) -- trigger GC
|
||||||
|
test.equal(gc.count(), 251)
|
||||||
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user