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:
parent
5a1632adba
commit
8e39f07112
6 changed files with 84 additions and 5 deletions
|
@ -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));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
52
spec/mem/identity_mapping_spec.rb
Normal file
52
spec/mem/identity_mapping_spec.rb
Normal 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
|
|
@ -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] }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue