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

ensure idenity map entries are cleaned up:

This adds a regression for:

https://github.com/cowboyd/therubyracer/pull/336
This commit is contained in:
Charles Lowell 2015-08-15 17:58:46 +03:00
parent 5a1632adba
commit 8e39f07112
6 changed files with 84 additions and 5 deletions

View file

@ -5,12 +5,20 @@
namespace rr {
class Null : public Ref<v8::Value> {
public:
Null(v8::Isolate* isolate, v8::Local<v8::Value> undefined) :
Ref<v8::Value>(isolate, undefined) {}
static inline void Init() {
ClassBuilder("Null", Primitive::Class).
store(&Class);
//implement V8::C::Null(isolate)
rb_define_singleton_method(rb_eval_string("V8::C"), "Null", (VALUE (*)(...))&instance, 1);
}
Null(v8::Isolate* isolate, v8::Local<v8::Value> undefined) :
Ref<v8::Value>(isolate, undefined) {}
static VALUE instance(VALUE self, VALUE rb_isolate) {
Isolate isolate(rb_isolate);
Locker lock(isolate);
return Null(isolate, v8::Null(isolate));
}
};
}

View file

@ -119,6 +119,12 @@ module V8::C
end
end
class NilClass
def to_v8(context)
V8::C::Null(context.isolate.native)
end
end
##
# The following are the default conversions from Ruby objects into
# low-level C++ objects.

View file

@ -39,7 +39,14 @@ module V8
end
def []=(key, value)
@values[key] = V8::Weak::Ref.new(value)
V8::Weak::Ref.new(value).tap do |ref|
@values[key] = ref
ObjectSpace.define_finalizer(value, self.class.cleanup_entry(@values, key, ref))
end
end
def self.cleanup_entry(values, key, ref)
proc { values.delete(key) if values[key] == ref }
end
end
end
@ -70,4 +77,4 @@ module V8
end
end
end
end
end

View file

@ -0,0 +1,52 @@
require 'spec_helper'
describe "Identity Mapping Memory Usages" do
it "does not leak memory by virtue of maintaining an identity map" do
##
# This verifies that the identity map which is holds on to the
# mappings between v8 objects and ruby objects does not leak its
# entries as originally reported by this ticket:
# https://github.com/cowboyd/therubyracer/pull/336
#
# Without the patch, while the v8 object was not being leaked, the
# entry in the identity map was. This test injects 5000 objects
# into the v8 context 20 times over, which will generate 5000
# unique proxies. All of these proxies should be immediately released.
require 'memory_profiler'
def rss
`ps -eo pid,rss | grep #{Process.pid} | awk '{print $2}'`.to_i
end
cxt = V8::Context.new
Object.new.tap do |o|
cxt["object-#{o.object_id}"] = o
cxt["object-#{o.object_id}"] = nil
end
# MemoryProfiler has a helper that runs the GC multiple times to make
# sure all objects that can be freed are freed.
MemoryProfiler::Helpers.full_gc
start = rss
#puts "rss: #{rss} live objects #{GC.stat[:heap_live_slots]}"
20.times do
5000.times { |i|
Object.new.tap do |o|
cxt["object-#{o.object_id}"] = o
cxt["object-#{o.object_id}"] = nil
end
while cxt.isolate.native.IdleNotificationDeadline(0.1); end
}
MemoryProfiler::Helpers.full_gc
#puts "rss: #{rss} live objects #{GC.stat[:heap_live_slots]}"
end
finish = rss
expect(finish).to be <= start * 2.5
end if RUBY_VERSION >= "2.1.0"
end

View file

@ -141,6 +141,10 @@ describe "V8::Context" do
@cxt = V8::Context.new
# @cxt['o'] = @instance
end
it "can embed nil into a context" do
@cxt['nil'] = nil
expect(@cxt['nil']).to be_nil
end
it "can embed a closure into a context and call it" do
@cxt["say"] = lambda { |*args| args[-2] * args[-1] }

View file

@ -19,4 +19,6 @@ Gem::Specification.new do |gem|
gem.add_dependency 'ref'
gem.add_dependency 'libv8', '~> 4.5.95.0'
gem.add_development_dependency 'memory_profiler'
end