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
|
test: all
|
||||||
@for i in test/test*.js; do \\
|
@for i in test/test*.js; do \\
|
||||||
echo "\$\$i: "; \\
|
echo "\$\$i: "; \\
|
||||||
build/default/node \$\$i && echo PASS || echo FAIL; \\
|
build/debug/node \$\$i && echo PASS || echo FAIL; \\
|
||||||
done
|
done
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -487,7 +487,10 @@ Handle<Value>
|
|||||||
File::New(const Arguments& args)
|
File::New(const Arguments& args)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
new File(args.Holder());
|
|
||||||
|
File *f = new File(args.Holder());
|
||||||
|
ObjectWrap::InformV8ofAllocation(f);
|
||||||
|
|
||||||
return args.This();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ class File : ObjectWrap {
|
|||||||
public:
|
public:
|
||||||
static void Initialize (v8::Handle<v8::Object> target);
|
static void Initialize (v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
virtual size_t size (void) { return sizeof(File); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
File (v8::Handle<v8::Object> handle);
|
File (v8::Handle<v8::Object> handle);
|
||||||
~File ();
|
~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 = Persistent<FunctionTemplate>::New(t);
|
||||||
client_constructor_template->Inherit(Connection::constructor_template);
|
client_constructor_template->Inherit(Connection::constructor_template);
|
||||||
client_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
|
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);
|
t = FunctionTemplate::New(v8NewServer);
|
||||||
server_constructor_template = Persistent<FunctionTemplate>::New(t);
|
server_constructor_template = Persistent<FunctionTemplate>::New(t);
|
||||||
@ -57,7 +57,10 @@ Handle<Value>
|
|||||||
HTTPConnection::v8NewClient (const Arguments& args)
|
HTTPConnection::v8NewClient (const Arguments& args)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
new HTTPConnection(args.This(), HTTP_RESPONSE);
|
|
||||||
|
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_RESPONSE);
|
||||||
|
ObjectWrap::InformV8ofAllocation(connection);
|
||||||
|
|
||||||
return args.This();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +68,10 @@ Handle<Value>
|
|||||||
HTTPConnection::v8NewServer (const Arguments& args)
|
HTTPConnection::v8NewServer (const Arguments& args)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
new HTTPConnection(args.This(), HTTP_REQUEST);
|
|
||||||
|
HTTPConnection *connection = new HTTPConnection(args.This(), HTTP_REQUEST);
|
||||||
|
ObjectWrap::InformV8ofAllocation(connection);
|
||||||
|
|
||||||
return args.This();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,6 +287,13 @@ HTTPConnection::HTTPConnection (Handle<Object> handle, enum http_parser_type typ
|
|||||||
parser_.data = this;
|
parser_.data = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HTTPConnection::~HTTPConnection ( )
|
||||||
|
{
|
||||||
|
V8::AdjustAmountOfExternalAllocatedMemory(-sizeof(HTTPConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Persistent<FunctionTemplate> HTTPServer::constructor_template;
|
Persistent<FunctionTemplate> HTTPServer::constructor_template;
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -312,7 +325,8 @@ HTTPServer::v8New (const Arguments& args)
|
|||||||
options = Object::New();
|
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();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ protected:
|
|||||||
|
|
||||||
HTTPConnection (v8::Handle<v8::Object> handle,
|
HTTPConnection (v8::Handle<v8::Object> handle,
|
||||||
enum http_parser_type type);
|
enum http_parser_type type);
|
||||||
|
~HTTPConnection ( );
|
||||||
|
|
||||||
void OnReceive (const void *buf, size_t len);
|
void OnReceive (const void *buf, size_t len);
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
||||||
|
|
||||||
|
|
||||||
HTTPServer (v8::Handle<v8::Object> handle,
|
HTTPServer (v8::Handle<v8::Object> handle,
|
||||||
v8::Handle<v8::Function> protocol_class,
|
v8::Handle<v8::Function> protocol_class,
|
||||||
v8::Handle<v8::Object> options)
|
v8::Handle<v8::Object> options)
|
||||||
|
18
src/net.cc
18
src/net.cc
@ -145,7 +145,10 @@ Handle<Value>
|
|||||||
Connection::v8New (const Arguments& args)
|
Connection::v8New (const Arguments& args)
|
||||||
{
|
{
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
new Connection(args.This());
|
|
||||||
|
Connection *c = new Connection(args.This());
|
||||||
|
ObjectWrap::InformV8ofAllocation(c);
|
||||||
|
|
||||||
return args.This();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +277,16 @@ Connection::v8Send (const Arguments& args)
|
|||||||
Connection *connection = NODE_UNWRAP(Connection, args.Holder());
|
Connection *connection = NODE_UNWRAP(Connection, args.Holder());
|
||||||
if (!connection) return Handle<Value>();
|
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()) {
|
if (args[0]->IsString()) {
|
||||||
// utf8 encoding
|
// utf8 encoding
|
||||||
Local<String> s = args[0]->ToString();
|
Local<String> s = args[0]->ToString();
|
||||||
@ -451,7 +464,8 @@ Acceptor::v8New (const Arguments& args)
|
|||||||
options = Object::New();
|
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();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ class Connection : public ObjectWrap {
|
|||||||
public:
|
public:
|
||||||
static void Initialize (v8::Handle<v8::Object> target);
|
static void Initialize (v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
virtual size_t size (void) { return sizeof(Connection); };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* v8 interface */
|
/* v8 interface */
|
||||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||||
@ -100,6 +102,8 @@ class Acceptor : public ObjectWrap {
|
|||||||
public:
|
public:
|
||||||
static void Initialize (v8::Handle<v8::Object> target);
|
static void Initialize (v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
virtual size_t size (void) { return sizeof(Acceptor); };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||||
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
static v8::Handle<v8::Value> v8New (const v8::Arguments& args);
|
||||||
@ -109,7 +113,7 @@ protected:
|
|||||||
Acceptor (v8::Handle<v8::Object> handle,
|
Acceptor (v8::Handle<v8::Object> handle,
|
||||||
v8::Handle<v8::Function> connection_handler,
|
v8::Handle<v8::Function> connection_handler,
|
||||||
v8::Handle<v8::Object> options);
|
v8::Handle<v8::Object> options);
|
||||||
virtual ~Acceptor () { Close(); puts("acceptor gc'd!");}
|
virtual ~Acceptor () { Close(); }
|
||||||
|
|
||||||
v8::Local<v8::Function> GetConnectionHandler (void);
|
v8::Local<v8::Function> GetConnectionHandler (void);
|
||||||
|
|
||||||
|
11
src/node.cc
11
src/node.cc
@ -53,8 +53,10 @@ ObjectWrap::Detach ()
|
|||||||
if (attach_count_ > 0)
|
if (attach_count_ > 0)
|
||||||
attach_count_ -= 1;
|
attach_count_ -= 1;
|
||||||
|
|
||||||
if(weak_ && attach_count_ == 0)
|
if(weak_ && attach_count_ == 0) {
|
||||||
|
V8::AdjustAmountOfExternalAllocatedMemory(-size());
|
||||||
delete this;
|
delete this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
@ -87,6 +89,12 @@ ObjectWrap::MakeWeak (Persistent<Value> _, void *data)
|
|||||||
delete obj;
|
delete obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ObjectWrap::InformV8ofAllocation (ObjectWrap *obj)
|
||||||
|
{
|
||||||
|
v8::V8::AdjustAmountOfExternalAllocatedMemory(obj->size());
|
||||||
|
}
|
||||||
|
|
||||||
// Extracts a C string from a V8 Utf8Value.
|
// Extracts a C string from a V8 Utf8Value.
|
||||||
const char*
|
const char*
|
||||||
ToCString(const v8::String::Utf8Value& value)
|
ToCString(const v8::String::Utf8Value& value)
|
||||||
@ -244,6 +252,7 @@ main (int argc, char *argv[])
|
|||||||
ev_async_init(&eio_watcher, node_eio_cb);
|
ev_async_init(&eio_watcher, node_eio_cb);
|
||||||
eio_init(eio_want_poll, NULL);
|
eio_init(eio_want_poll, NULL);
|
||||||
|
|
||||||
|
V8::Initialize();
|
||||||
V8::SetFlagsFromCommandLine(&argc, argv, true);
|
V8::SetFlagsFromCommandLine(&argc, argv, true);
|
||||||
|
|
||||||
if(argc < 2) {
|
if(argc < 2) {
|
||||||
|
@ -30,6 +30,11 @@ public:
|
|||||||
ObjectWrap (v8::Handle<v8::Object> handle);
|
ObjectWrap (v8::Handle<v8::Object> handle);
|
||||||
virtual ~ObjectWrap ( );
|
virtual ~ObjectWrap ( );
|
||||||
|
|
||||||
|
virtual size_t size (void) = 0;
|
||||||
|
|
||||||
|
/* This must be called after each new ObjectWrap creation! */
|
||||||
|
static void InformV8ofAllocation (node::ObjectWrap *obj);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void* Unwrap (v8::Handle<v8::Object> handle);
|
static void* Unwrap (v8::Handle<v8::Object> handle);
|
||||||
v8::Persistent<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 after = (double)(args[1]->IntegerValue()) / 1000.0;
|
||||||
ev_tstamp repeat = (double)(args[2]->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();
|
return args.This();
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ class Timer : ObjectWrap {
|
|||||||
public:
|
public:
|
||||||
static void Initialize (v8::Handle<v8::Object> target);
|
static void Initialize (v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
virtual size_t size (void) { return sizeof(Timer); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
static v8::Persistent<v8::FunctionTemplate> constructor_template;
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
p({hello: "world"});
|
|
||||||
new node.http.Server(function (msg) {
|
new node.http.Server(function (msg) {
|
||||||
// setTimeout(function () {
|
setTimeout(function () {
|
||||||
msg.sendHeader(200, [["Content-Type", "text/plain"]]);
|
msg.sendHeader(200, [["Content-Type", "text/plain"]]);
|
||||||
msg.sendBody("Hello World");
|
msg.sendBody("Hello World");
|
||||||
msg.finish();
|
msg.finish();
|
||||||
// }, 1);
|
}, 1000);
|
||||||
}).listen(8000, "localhost");
|
}).listen(8000, "localhost");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user