Skip to content

Commit 1f54fac

Browse files
committed
Merge pull request #222 from stesie/issue-217
Send LowMemoryNotification before imposing memory limit
2 parents c804b16 + 3dca462 commit 1f54fac

File tree

2 files changed

+54
-15
lines changed

2 files changed

+54
-15
lines changed

v8js_timer.cc

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,47 @@ static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /*
4040

4141
v8::Locker locker(isolate);
4242
v8::HeapStatistics hs;
43-
isolate->GetHeapStatistics(&hs);
43+
bool send_notification = false;
44+
bool has_sent_notification = false;
4445

45-
V8JSG(timer_mutex).lock();
46+
do {
47+
if (send_notification) {
48+
#if PHP_V8_API_VERSION >= 3028036
49+
isolate->LowMemoryNotification();
50+
#else
51+
v8::V8::LowMemoryNotification();
52+
#endif
53+
has_sent_notification = true;
54+
}
4655

47-
for (std::deque< v8js_timer_ctx* >::iterator it = V8JSG(timer_stack).begin();
48-
it != V8JSG(timer_stack).end(); it ++) {
49-
v8js_timer_ctx *timer_ctx = *it;
50-
v8js_ctx *c = timer_ctx->ctx;
56+
isolate->GetHeapStatistics(&hs);
5157

52-
if(c->isolate != isolate || timer_ctx->killed) {
53-
continue;
54-
}
58+
V8JSG(timer_mutex).lock();
59+
60+
for (std::deque< v8js_timer_ctx* >::iterator it = V8JSG(timer_stack).begin();
61+
it != V8JSG(timer_stack).end(); it ++) {
62+
v8js_timer_ctx *timer_ctx = *it;
63+
v8js_ctx *c = timer_ctx->ctx;
64+
65+
if(c->isolate != isolate || timer_ctx->killed) {
66+
continue;
67+
}
5568

56-
if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
57-
timer_ctx->killed = true;
58-
v8::V8::TerminateExecution(c->isolate);
59-
c->memory_limit_hit = true;
69+
if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
70+
if (has_sent_notification) {
71+
timer_ctx->killed = true;
72+
v8::V8::TerminateExecution(c->isolate);
73+
c->memory_limit_hit = true;
74+
} else {
75+
// force garbage collection, then check again
76+
send_notification = true;
77+
break;
78+
}
79+
}
6080
}
61-
}
6281

63-
V8JSG(timer_mutex).unlock();
82+
V8JSG(timer_mutex).unlock();
83+
} while(send_notification != has_sent_notification);
6484
}
6585
/* }}} */
6686

v8js_v8.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,25 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
204204
return;
205205
}
206206

207+
if (memory_limit && !c->memory_limit_hit) {
208+
// Re-check memory limit (very short executions might never be hit by timer thread)
209+
v8::HeapStatistics hs;
210+
isolate->GetHeapStatistics(&hs);
211+
212+
if (hs.used_heap_size() > memory_limit) {
213+
#if PHP_V8_API_VERSION >= 3028036
214+
isolate->LowMemoryNotification();
215+
#else
216+
v8::V8::LowMemoryNotification();
217+
#endif
218+
isolate->GetHeapStatistics(&hs);
219+
220+
if (hs.used_heap_size() > memory_limit) {
221+
c->memory_limit_hit = true;
222+
}
223+
}
224+
}
225+
207226
if (c->memory_limit_hit) {
208227
// Execution has been terminated due to memory limit
209228
sprintf(exception_string, "Script memory limit of %lu bytes exceeded", memory_limit);

0 commit comments

Comments
 (0)