1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

add back the basics of memory testing.

This adds back the memory tests which ensure The Ruby Racer's
stability. It also includes the changes needed to make these initial
specs pass.

At this point to disallow calling Dispose() directly on the underlying
Isolate. If you do, then you could have all of the Ruby objects happily
sitting in memory, but trying to use them would result in a segfault for
trying to use a dead isolate. In order to avoid that, we'd have to put
in safeguards everywhere to make sure for any operation on any context
or object, that it's isolate was still alive.

In order to reduce the complexity of memory management, the safest thing
is to let the garbage collection hook dispose of the isolate
itself. That way there is no doubt that the isolate is no longer in use.
This commit is contained in:
Charles Lowell 2015-07-28 17:57:01 +03:00
parent 78ac679a7a
commit d969b1cdb9
4 changed files with 30 additions and 17 deletions

View file

@ -24,6 +24,7 @@ script:
- bundle exec rake compile
- bundle exec rspec spec/c
- bundle exec rspec spec/v8/context_spec.rb
- bundle exec rspec spec/mem
sudo: false
addons:
apt:

View file

@ -11,7 +11,7 @@ namespace rr {
ClassBuilder("Isolate").
defineSingletonMethod("New", &New).
defineMethod("Dispose", &Isolate::Dispose).
defineMethod("IdleNotificationDeadline", &IdleNotificationDeadline).
store(&Class);
}
@ -26,7 +26,6 @@ namespace rr {
create_params.array_buffer_allocator = &data->array_buffer_allocator;
v8::Isolate* isolate = v8::Isolate::New(create_params);
isolate->SetData(0, data);
isolate->AddGCPrologueCallback(&clearReferences);
@ -34,9 +33,10 @@ namespace rr {
return Isolate(isolate);
}
VALUE Isolate::Dispose(VALUE self) {
VALUE Isolate::IdleNotificationDeadline(VALUE self, VALUE deadline_in_seconds) {
Isolate isolate(self);
isolate->Dispose();
return Qnil;
Locker lock(isolate);
return Bool(isolate->IdleNotificationDeadline(NUM2DBL(deadline_in_seconds)));
}
}

View file

@ -50,6 +50,7 @@ namespace rr {
*/
static void destroy(IsolateData* data) {
Isolate isolate(data);
isolate->Dispose();
isolate.decrementTotalReferences();
}
@ -159,7 +160,15 @@ namespace rr {
while (data->rb_release_queue.try_dequeue(object)) {
isolate.releaseObject(object);
}
rb_gc_mark(data->retained_objects);
//TODO: This should not be necessary since sometimes the
//instance of V8::RetainedObjects appears to magically be of
//type T_NONE instead of T_OBJECT. Later, it will be T_OBJECT,
//but if called while T_NONE, it will cause rb_gc_mark to dump
//core.
//See https://bugs.ruby-lang.org/issues/10803
if (TYPE(data->retained_objects) != T_NONE) {
rb_gc_mark(data->retained_objects);
}
}
/**
@ -177,7 +186,7 @@ namespace rr {
}
static VALUE Dispose(VALUE self);
static VALUE IdleNotificationDeadline(VALUE self, VALUE deadline_in_seconds);
/**
* Recent versions of V8 will segfault unless you pass in an

View file

@ -7,7 +7,7 @@ describe "A Very blunt test to make sure that we aren't doing stupid leaks", :me
end
#allocate a single context to make sure that v8 loads its snapshot and
#we pay the overhead.
V8::Context.new
V8::Isolate.new
@start_memory = process_memory
GC.stress = true
end
@ -15,23 +15,27 @@ describe "A Very blunt test to make sure that we aren't doing stupid leaks", :me
after do
GC.stress = false
end
it "can create 3 isolates in a row" do
3.times { V8::Isolate.new }
end
it "won't increase process memory by more than 50% no matter how many contexts we create" do
500.times do
V8::Context.new
run_v8_gc
250.times do
isolate = V8::Context.new.isolate.native
isolate.IdleNotificationDeadline(0.1)
end
process_memory.should <= @start_memory * 1.5
expect(process_memory).to be <= @start_memory * 1.5
end
it "can eval simple value passing statements repeatedly without significantly increasing memory" do
V8::C::Locker() do
cxt = V8::Context.new
V8::Context.new do |cxt|
500.times do
cxt.eval('7 * 6')
run_v8_gc
cxt.isolate.native.IdleNotificationDeadline(0.1)
end
end
process_memory.should <= @start_memory * 1.1
expect(process_memory).to be <= @start_memory * 1.1
end
def process_memory
@ -39,4 +43,3 @@ describe "A Very blunt test to make sure that we aren't doing stupid leaks", :me
end
end