Inform V8 of external allocations.
This is sloppy: after each ObjectWrap allocation the user needs to call ObjectWrap::InformV8ofAllocation(). In addition each class deriving from ObjectWrap needs to implement the virtual method size() which should return the size of the derived class. If I was better at C++ I could possibly make this less ugly. For now this is how it is. Memory usage looks much better after this commit.
This commit is contained in:
parent
81691c7dc5
commit
baed9d514d
2
configure
vendored
2
configure
vendored
@ -95,7 +95,7 @@ uninstall:
|
||||
test: all
|
||||
@for i in test/test*.js; do \\
|
||||
echo "\$\$i: "; \\
|
||||
build/default/node \$\$i && echo PASS || echo FAIL; \\
|
||||
build/debug/node \$\$i && echo PASS || echo FAIL; \\
|
||||
done
|
||||
|
||||
clean:
|
||||
|
@ -487,7 +487,10 @@ Handle<Value>
|
||||
File::New(const Arguments& args)
|
||||
{
|
||||
HandleScope scope;
|
||||
new File(args.Holder());
|
||||
|
||||
File *f = new File(args.Holder());
|
||||
ObjectWrap::InformV8ofAllocation(f);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,8 @@ class File : ObjectWrap {
|
||||
public:
|
||||
static void Initialize (v8::Handle<v8::Object> target);
|
||||
|
||||
virtual size_t size (void) { return sizeof(File); }
|
||||
|
||||
protected:
|
||||
File (v8::Handle<v8::Object> handle);
|
||||
~File ();
|
||||
|
22
src/http.cc
22
src/http.cc
@ -43,7 +43,7 @@ HTTPConnection::Initialize (Handle<Object> target)
|
||||
client_constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||
client_constructor_template->Inherit(Connection::constructor_template);
|
||||
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
target->Set(String::NewSymbol("Client"), client_constructor_template->GetFunction());
|
||||
target->Set(String::NewSymbol("LowLevelClient"), client_constructor_template->GetFunction());
|
||||
|
||||
t = FunctionTemplate::New(v8NewServer);
|
||||
server_constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||
@ -57,7 +57,10 @@ Handle<Value>
|
||||
HTTPConnection::v8NewClient (const Arguments& args)
|
||||
{
|
||||
HandleScope scope;
|
||||
new HTTPConnection(args.This(), HTTP_RESPONSE);
|
||||
|
||||
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_RESPONSE);
|
||||
ObjectWrap::InformV8ofAllocation(connection);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
@ -65,7 +68,10 @@ Handle<Value>
|
||||
HTTPConnection::v8NewServer (const Arguments& args)
|
||||
{
|
||||
HandleScope scope;
|
||||
new HTTPConnection(args.This(), HTTP_REQUEST);
|
||||
|
||||
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_REQUEST);
|
||||
ObjectWrap::InformV8ofAllocation(connection);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
@ -281,6 +287,13 @@ HTTPConnection::HTTPConnection (Handle<Object> handle, enum http_parser_type typ
|
||||
parser_.data = this;
|
||||
}
|
||||
|
||||
|
||||
HTTPConnection::~HTTPConnection ( )
|
||||
{
|
||||
V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(HTTPConnection));
|
||||
}
|
||||
|
||||
|
||||
Persistent<FunctionTemplate> HTTPServer::constructor_template;
|
||||
|
||||
void
|
||||
@ -312,7 +325,8 @@ HTTPServer::v8New (const Arguments& args)
|
||||
options = Object::New();
|
||||
}
|
||||
|
||||
new HTTPServer(args.This(), protocol_class, options);
|
||||
HTTPServer *s = new HTTPServer(args.This(), protocol_class, options);
|
||||
ObjectWrap::InformV8ofAllocation(s);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ protected:
|
||||
|
||||
HTTPConnection (v8::Handle<v8::Object> handle,
|
||||
enum http_parser_type type);
|
||||
~HTTPConnection ( );
|
||||
|
||||
void OnReceive (const void *buf, size_t len);
|
||||
|
||||
@ -47,6 +48,7 @@ public:
|
||||
protected:
|
||||
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
||||
|
||||
|
||||
HTTPServer (v8::Handle<v8::Object> handle,
|
||||
v8::Handle<v8::Function> protocol_class,
|
||||
v8::Handle<v8::Object> options)
|
||||
|
18
src/net.cc
18
src/net.cc
@ -145,7 +145,10 @@ Handle<Value>
|
||||
Connection::v8New (const Arguments& args)
|
||||
{
|
||||
HandleScope scope;
|
||||
new Connection(args.This());
|
||||
|
||||
Connection *c = new Connection(args.This());
|
||||
ObjectWrap::InformV8ofAllocation(c);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
||||
@ -274,6 +277,16 @@ Connection::v8Send (const Arguments& args)
|
||||
Connection *connection = NODE_UNWRAP(Connection, args.Holder());
|
||||
if (!connection) return Handle<Value>();
|
||||
|
||||
// XXX
|
||||
// A lot of improvement can be made here. First of all we're allocating
|
||||
// oi_bufs for every send which is clearly inefficent - it should use a
|
||||
// memory pool or ring buffer. In either case, v8 needs to be informed
|
||||
// about our allocations deallocations via
|
||||
// V8::AdjustAmountOfExternalAllocatedMemory to give the GC hints about
|
||||
// what we're doing here. Of course, expressing binary data as an array
|
||||
// of integers is extremely inefficent. This can improved when v8 bug 270
|
||||
// (http://code.google.com/p/v8/issues/detail?id=270) has been addressed.
|
||||
|
||||
if (args[0]->IsString()) {
|
||||
// utf8 encoding
|
||||
Local<String> s = args[0]->ToString();
|
||||
@ -451,7 +464,8 @@ Acceptor::v8New (const Arguments& args)
|
||||
options = Object::New();
|
||||
}
|
||||
|
||||
new Acceptor(args.This(), connection_handler, options);
|
||||
Acceptor *a = new Acceptor(args.This(), connection_handler, options);
|
||||
ObjectWrap::InformV8ofAllocation(a);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ class Connection : public ObjectWrap {
|
||||
public:
|
||||
static void Initialize (v8::Handle<v8::Object> target);
|
||||
|
||||
virtual size_t size (void) { return sizeof(Connection); };
|
||||
|
||||
protected:
|
||||
/* v8 interface */
|
||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||
@ -100,6 +102,8 @@ class Acceptor : public ObjectWrap {
|
||||
public:
|
||||
static void Initialize (v8::Handle<v8::Object> target);
|
||||
|
||||
virtual size_t size (void) { return sizeof(Acceptor); };
|
||||
|
||||
protected:
|
||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
||||
@ -109,7 +113,7 @@ protected:
|
||||
Acceptor (v8::Handle<v8::Object> handle,
|
||||
v8::Handle<v8::Function> connection_handler,
|
||||
v8::Handle<v8::Object> options);
|
||||
virtual ~Acceptor () { Close(); puts("acceptor gc'd!");}
|
||||
virtual ~Acceptor () { Close(); }
|
||||
|
||||
v8::Local<v8::Function> GetConnectionHandler (void);
|
||||
|
||||
|
11
src/node.cc
11
src/node.cc
@ -53,8 +53,10 @@ ObjectWrap::Detach ()
|
||||
if (attach_count_ > 0)
|
||||
attach_count_ -= 1;
|
||||
|
||||
if(weak_ && attach_count_ == 0)
|
||||
if(weak_ && attach_count_ == 0) {
|
||||
V8::AdjustAmountOfExternalAllocatedMemory(-size());
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
@ -87,6 +89,12 @@ ObjectWrap::MakeWeak (Persistent<Value> _, void *data)
|
||||
delete obj;
|
||||
}
|
||||
|
||||
void
|
||||
ObjectWrap::InformV8ofAllocation (ObjectWrap *obj)
|
||||
{
|
||||
v8::V8::AdjustAmountOfExternalAllocatedMemory(obj->size());
|
||||
}
|
||||
|
||||
// Extracts a C string from a V8 Utf8Value.
|
||||
const char*
|
||||
ToCString(const v8::String::Utf8Value& value)
|
||||
@ -244,6 +252,7 @@ main (int argc, char *argv[])
|
||||
ev_async_init(&eio_watcher, node_eio_cb);
|
||||
eio_init(eio_want_poll, NULL);
|
||||
|
||||
V8::Initialize();
|
||||
V8::SetFlagsFromCommandLine(&argc, argv, true);
|
||||
|
||||
if(argc < 2) {
|
||||
|
@ -30,6 +30,11 @@ public:
|
||||
ObjectWrap (v8::Handle<v8::Object> handle);
|
||||
virtual ~ObjectWrap ( );
|
||||
|
||||
virtual size_t size (void) = 0;
|
||||
|
||||
/* This must be called after each new ObjectWrap creation! */
|
||||
static void InformV8ofAllocation (node::ObjectWrap *obj);
|
||||
|
||||
protected:
|
||||
static void* Unwrap (v8::Handle<v8::Object> handle);
|
||||
v8::Persistent<v8::Object> handle_;
|
||||
|
@ -80,7 +80,8 @@ Timer::New (const Arguments& args)
|
||||
ev_tstamp after = (double)(args[1]->IntegerValue()) / 1000.0;
|
||||
ev_tstamp repeat = (double)(args[2]->IntegerValue()) / 1000.0;
|
||||
|
||||
new Timer(args.Holder(), callback, after, repeat);
|
||||
Timer *t = new Timer(args.Holder(), callback, after, repeat);
|
||||
ObjectWrap::InformV8ofAllocation(t);
|
||||
|
||||
return args.This();
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ class Timer : ObjectWrap {
|
||||
public:
|
||||
static void Initialize (v8::Handle<v8::Object> target);
|
||||
|
||||
virtual size_t size (void) { return sizeof(Timer); }
|
||||
|
||||
protected:
|
||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
p({hello: "world"});
|
||||
new node.http.Server(function (msg) {
|
||||
// setTimeout(function () {
|
||||
setTimeout(function () {
|
||||
msg.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||
msg.sendBody("Hello World");
|
||||
msg.finish();
|
||||
// }, 1);
|
||||
}, 1000);
|
||||
}).listen(8000, "localhost");
|
||||
|
Loading…
x
Reference in New Issue
Block a user