Skip to content

Commit

Permalink
Inform V8 of external allocations.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ry committed May 15, 2009
1 parent 81691c7 commit baed9d5
Show file tree
Hide file tree
Showing 12 changed files with 69 additions and 14 deletions.
2 changes: 1 addition & 1 deletion configure
Expand Up @@ -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:
Expand Down
5 changes: 4 additions & 1 deletion src/file.cc
Expand Up @@ -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();
}

2 changes: 2 additions & 0 deletions src/file.h
Expand Up @@ -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 ();
Expand Down
22 changes: 18 additions & 4 deletions src/http.cc
Expand Up @@ -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);
Expand All @@ -57,15 +57,21 @@ 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();
}

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();
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
Expand Down
2 changes: 2 additions & 0 deletions src/http.h
Expand Up @@ -20,6 +20,7 @@ class HTTPConnection : public Connection {

HTTPConnection (v8::Handle<v8::Object> handle,
enum http_parser_type type);
~HTTPConnection ( );

void OnReceive (const void *buf, size_t len);

Expand Down Expand Up @@ -47,6 +48,7 @@ class HTTPServer : public Acceptor {
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)
Expand Down
18 changes: 16 additions & 2 deletions src/net.cc
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
}
Expand Down
6 changes: 5 additions & 1 deletion src/net.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -109,7 +113,7 @@ class Acceptor : public ObjectWrap {
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);

Expand Down
11 changes: 10 additions & 1 deletion src/node.cc
Expand Up @@ -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*
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions src/node.h
Expand Up @@ -30,6 +30,11 @@ class ObjectWrap {
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_;
Expand Down
3 changes: 2 additions & 1 deletion src/timer.cc
Expand Up @@ -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();
}
Expand Down
2 changes: 2 additions & 0 deletions src/timer.h
Expand Up @@ -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;

Expand Down
5 changes: 2 additions & 3 deletions test_http.js
@@ -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");

0 comments on commit baed9d5

Please sign in to comment.