Skip to content

Commit 3deea01

Browse files
committed
Call uni::AdjustAmountOfExternalAllocatedMemory less often.
Apparently calling v8::Isolate::AdjustAmountOfExternalAllocatedMemory frequently results in lots of wasted CPU cycles on garbage collection, per discussion here: meteor/meteor#10527 (comment) This fix was inspired by marudor/libxmljs2#22, which seems to have addressed nodejs/node#30995. Another project that benefitted from adjusting external allocated memory less often: mapnik/node-mapnik#136
1 parent f882017 commit 3deea01

File tree

1 file changed

+35
-2
lines changed

1 file changed

+35
-2
lines changed

Diff for: src/fibers.cc

+35-2
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,13 @@ class Fiber {
412412
static vector<Fiber*> orphaned_fibers;
413413
static Persistent<Value> fatal_stack;
414414

415+
static size_t external_bytes_used;
416+
static size_t external_bytes_reported;
417+
// We report external memory usage only when the difference
418+
// between used and reported exceeds threshold, to avoid calling
419+
// uni::AdjustAmountOfExternalAllocatedMemory too often.
420+
static int external_bytes_threshold;
421+
415422
Isolate* isolate;
416423
Persistent<Object> handle;
417424
Persistent<Function> cb;
@@ -578,7 +585,7 @@ class Fiber {
578585
THROW(Exception::RangeError, "Out of memory");
579586
}
580587
that.started = true;
581-
uni::AdjustAmountOfExternalAllocatedMemory(that.isolate, that.this_fiber->size() * GC_ADJUST);
588+
AdjustExternalMemoryOnFiberStart(that);
582589
} else {
583590
// If the fiber is currently running put the first parameter to `run()` on `yielded`, then
584591
// the pending call to `yield()` will return that value. `yielded` in this case is just a
@@ -760,7 +767,7 @@ class Fiber {
760767

761768
// Do not invoke the garbage collector if there's no context on the stack. It will seg fault
762769
// otherwise.
763-
uni::AdjustAmountOfExternalAllocatedMemory(that.isolate, -(int)(that.this_fiber->size() * GC_ADJUST));
770+
AdjustExternalMemoryOnFiberExit(that);
764771

765772
// Don't make weak until after notifying the garbage collector. Otherwise it may try and
766773
// free this very fiber!
@@ -859,6 +866,24 @@ class Fiber {
859866
return uni::Return(uni::NewNumber(Isolate::GetCurrent(), Coroutine::coroutines_created()), info);
860867
}
861868

869+
static void AdjustExternalMemoryOnFiberStart(const Fiber& fiber) {
870+
external_bytes_used += fiber.this_fiber->size() * GC_ADJUST;
871+
int diff = external_bytes_used - external_bytes_reported;
872+
if (diff > external_bytes_threshold) {
873+
uni::AdjustAmountOfExternalAllocatedMemory(fiber.isolate, diff);
874+
external_bytes_reported = external_bytes_used;
875+
}
876+
}
877+
878+
static void AdjustExternalMemoryOnFiberExit(const Fiber& fiber) {
879+
external_bytes_used -= fiber.this_fiber->size() * GC_ADJUST;
880+
int diff = external_bytes_used - external_bytes_reported;
881+
if (-diff > external_bytes_threshold) {
882+
uni::AdjustAmountOfExternalAllocatedMemory(fiber.isolate, diff);
883+
external_bytes_reported = external_bytes_used;
884+
}
885+
}
886+
862887
public:
863888
/**
864889
* Initialize the Fiber library.
@@ -918,6 +943,14 @@ Locker* Fiber::global_locker;
918943
Fiber* Fiber::current = NULL;
919944
vector<Fiber*> Fiber::orphaned_fibers;
920945
Persistent<Value> Fiber::fatal_stack;
946+
947+
// Used by AdjustExternalMemoryOnFiber{Start,Exit} to avoid calling
948+
// uni::AdjustAmountOfExternalAllocatedMemory every time a Fiber starts
949+
// or exits.
950+
size_t Fiber::external_bytes_used = 0;
951+
size_t Fiber::external_bytes_reported = 0;
952+
int Fiber::external_bytes_threshold = 1024 * 1024;
953+
921954
bool did_init = false;
922955

923956
#if !NODE_VERSION_AT_LEAST(0,10,0)

0 commit comments

Comments
 (0)