Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
3bc27f8
Fixed v8::IdleNotification for nodejs 0.12
Feb 7, 2015
a9e1443
Fixed v8::IdleNotification for nodejs 0.12
Feb 7, 2015
ce306b3
Update package.json
Feb 7, 2015
708c3cf
Fixed v8::IdleNotification for nodejs 0.12
Feb 7, 2015
c736f94
Updated package.json file.
Mar 30, 2015
c1d8026
Link to the right git repository
markusdap May 7, 2015
8aa5f8f
Merge pull request #1 from Globegitter/patch-1
May 7, 2015
b7db604
Updated package.json file.
May 7, 2015
b70ee74
Fixed nodegyp broken by path with spaces.
May 7, 2015
99614a3
Updated package.json file.
May 7, 2015
a308f77
Update module name in README
jguepin May 12, 2015
29b4ffc
Merge pull request #2 from chmod0/master
May 12, 2015
e816eca
Update package.json
May 12, 2015
d1b66c4
Added iojs to Travis CI
May 12, 2015
661f35b
Update package.json
May 12, 2015
9b619fc
fix(bindings): support for npm@3 flatness
Zertz Jun 26, 2015
09059eb
fix readme
doron2402 Jul 9, 2015
2a62b9e
Merge pull request #4 from doron2402/master
Jul 10, 2015
a8133e3
Merge pull request #3 from Zertz/patch-1
Jul 10, 2015
f88aa00
Bump version 0.2.7
Jul 11, 2015
1dcfda8
include iojs-v3 in travis ci build
trshafer Aug 19, 2015
165dcec
Upgraded NaN to 2.x.
Aug 20, 2015
64dd89e
Fixed support for iojs/nodejs version < 3.x with Nan 2.x.
Aug 21, 2015
1dbb83d
Bump version 0.2.8
Aug 21, 2015
5aa67b6
Merge pull request #5 from amplii/build-iojsv3
Aug 21, 2015
cb5fe9f
Reworked gc() implementation.
Aug 21, 2015
3c624fd
Bump version 0.2.9
Aug 21, 2015
ae8e23d
Merge branch 'master' of https://github.com/marcominetti/node-memwatch
Aug 21, 2015
b4d6bb2
Make compatible with Alpine linux by using cmath instead of math.h
toddbluhm Nov 3, 2015
3d90653
Merge pull request #6 from toddbluhm/master
Nov 9, 2015
d586015
Bump version 0.2.10
Nov 9, 2015
08617bd
Update README.md
akras14 Dec 22, 2015
530ae47
Merge pull request #7 from akras14/patch-1
Dec 23, 2015
fc1b88d
chore(ci): add Node 4, 5 & 6
Zertz Apr 27, 2016
61621be
Merge pull request #16 from Zertz/patch-1
Apr 30, 2016
436ce0d
Updated dependencies, travis targets and bump version 0.3.0.
Apr 30, 2016
f05f77d
Fix travis ci build for nodejs 4+.
Apr 30, 2016
23b2da5
Fix travis ci build for nodejs 4+.
Apr 30, 2016
35aad77
update license page
varatep Sep 23, 2016
35a9b61
aver --> after ?
eklem Jan 27, 2017
4dd8f06
Merge pull request #29 from eklem/patch-1
Jan 27, 2017
f280330
Merge pull request #21 from varatep/master
Jan 27, 2017
b638c90
Update README.md
marcominetti Mar 22, 2021
de2ee6f
Update README.md
jorisw Dec 29, 2022
202ad62
Merge pull request #53 from jorisw/patch-1
marcominetti Dec 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
language: node_js

env:
- CXX=g++-4.8
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
node_js:
- 0.10
- 0.11
- "0.10"
- "0.12"
- "4"
- "5"
- "6"
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# This project is DEPRECATED

See https://github.com/airbnb/node-memwatch for an actively maintained fork.


`node-memwatch`: Leak Detection and Heap Diffing for Node.JS
============================================================

Expand All @@ -19,11 +24,11 @@ Node.JS code. It provides:
Installation
------------

- `npm install memwatch`
- `npm install memwatch-next`

or

- `git clone git://github.com/lloyd/node-memwatch.git`
- `git clone git://github.com/marcominetti/node-memwatch.git`


Description
Expand All @@ -37,7 +42,7 @@ instrumentation. This module attempts to satisfy that need.
To get started, import `node-memwatch` like so:

```javascript
var memwatch = require('memwatch');
var memwatch = require('memwatch-next');
```

### Leak Detection
Expand All @@ -63,7 +68,7 @@ The `info` object will look something like:
### Heap Usage

The best way to evaluate your memory footprint is to look at heap
usage right aver V8 performs garbage collection. `memwatch` does
usage right after V8 performs garbage collection. `memwatch` does
exactly this - it checks heap usage only after GC to give you a stable
baseline of your actual memory usage.

Expand Down Expand Up @@ -136,6 +141,7 @@ The contents of `diff` will look something like:
}
]
}
}
```

The diff shows that during the sample period, the total number of
Expand All @@ -156,4 +162,4 @@ Please see the Issues to share suggestions and contribute!
License
-------

http://wtfpl.org
http://wtfpl.net
2 changes: 1 addition & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
'target_name': 'memwatch',
'include_dirs': [
'<!(node -p -e "require(\'path\').dirname(require.resolve(\'nan\'))")'
"<!(node -e \"require('nan')\")"
],
'sources': [
'src/heapdiff.cc',
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "memwatch",
"name": "memwatch-next",
"description": "Keep an eye on your memory usage, and discover and isolate leaks.",
"version": "0.2.2",
"version": "0.3.0",
"author": "Lloyd Hilaiel (http://lloyd.io)",
"engines": {
"node": ">= 0.8.0"
},
"repository": {
"type": "git",
"url": "https://github.com/lloyd/node-memwatch.git"
"url": "https://github.com/marcominetti/node-memwatch.git"
},
"main": "include.js",
"licenses": [
Expand All @@ -17,23 +17,23 @@
}
],
"bugs": {
"url": "https://github.com/lloyd/node-memwatch/issues"
"url": "https://github.com/marcominetti/node-memwatch/issues"
},
"scripts": {
"install": "node-gyp rebuild",
"test": "mocha tests --reporter spec"
},
"devDependencies": {
"mocha": "1.2.2",
"should": "0.6.3"
"mocha": "^2.4.5",
"should": "^8.3.1"
},
"contributors": [
"Jed Parsons (@jedp)",
"Jeff Haynie (@jhaynie)",
"Justin Matthews (@jmatthewsr-ms)"
],
"dependencies": {
"bindings": "^1.2.0",
"nan": "^1.2.0"
"bindings": "^1.2.1",
"nan": "^2.3.2"
}
}
121 changes: 68 additions & 53 deletions src/heapdiff.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,45 +45,49 @@ heapdiff::HeapDiff::~HeapDiff()
void
heapdiff::HeapDiff::Initialize ( v8::Handle<v8::Object> target )
{
NanScope();
Nan::HandleScope scope;

v8::Local<v8::FunctionTemplate> t = NanNew<v8::FunctionTemplate>(New);
v8::Local<v8::FunctionTemplate> t = Nan::New<v8::FunctionTemplate>(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(NanNew("HeapDiff"));
t->SetClassName(Nan::New<v8::String>("HeapDiff").ToLocalChecked());

NODE_SET_PROTOTYPE_METHOD(t, "end", End);
Nan::SetPrototypeMethod(t, "end", End);

target->Set(NanNew( "HeapDiff"), t->GetFunction());
target->Set(Nan::New<v8::String>("HeapDiff").ToLocalChecked(), t->GetFunction());
}

NAN_METHOD(heapdiff::HeapDiff::New)
{
// Don't blow up when the caller says "new require('memwatch').HeapDiff()"
// issue #30
// stolen from: https://github.com/kkaefer/node-cpp-modules/commit/bd9432026affafd8450ecfd9b49b7dc647b6d348
if (!args.IsConstructCall()) {
return NanThrowTypeError("Use the new operator to create instances of this object.");
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Use the new operator to create instances of this object.");
}

NanScope();
Nan::HandleScope scope;

// allocate the underlying c++ class and wrap it up in the this pointer
HeapDiff * self = new HeapDiff();
self->Wrap(args.This());
self->Wrap(info.This());

// take a snapshot and save a pointer to it
s_inProgress = true;
s_startTime = time(NULL);

#if (NODE_MODULE_VERSION >= 0x002D)
self->before = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(NULL);
#else
#if (NODE_MODULE_VERSION > 0x000B)
self->before = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(NanNew<v8::String>(""), NULL);
self->before = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(Nan::New<v8::String>("").ToLocalChecked(), NULL);
#else
self->before = v8::HeapProfiler::TakeSnapshot(NanNew<v8::String>(""), HeapSnapshot::kFull, NULL);
self->before = v8::HeapProfiler::TakeSnapshot(Nan::New<v8::String>("").ToLocalChecked(), HeapSnapshot::kFull, NULL);
#endif
#endif

s_inProgress = false;

NanReturnValue(args.This());
info.GetReturnValue().Set(info.This());
}

static string handleToStr(const Handle<Value> & str)
Expand All @@ -95,7 +99,7 @@ static string handleToStr(const Handle<Value> & str)
static void
buildIDSet(set<uint64_t> * seen, const HeapGraphNode* cur, int & s)
{
NanScope();
Nan::HandleScope scope;

// cycle detection
if (seen->find(cur->GetId()) != seen->end()) {
Expand All @@ -109,8 +113,11 @@ buildIDSet(set<uint64_t> * seen, const HeapGraphNode* cur, int & s)
}

// update memory usage as we go
#if (NODE_MODULE_VERSION >= 0x002D)
s += cur->GetShallowSize();
#else
s += cur->GetSelfSize();

#endif
seen->insert(cur->GetId());

for (int i=0; i < cur->GetChildrenCount(); i++) {
Expand Down Expand Up @@ -200,7 +207,11 @@ static void manageChange(changeset & changes, const HeapGraphNode * node, bool a

changeset::iterator i = changes.find(type);

#if (NODE_MODULE_VERSION >= 0x002D)
i->second.size += node->GetShallowSize() * (added ? 1 : -1);
#else
i->second.size += node->GetSelfSize() * (added ? 1 : -1);
#endif
if (added) i->second.added++;
else i->second.released++;

Expand All @@ -211,66 +222,66 @@ static void manageChange(changeset & changes, const HeapGraphNode * node, bool a

static Handle<Value> changesetToObject(changeset & changes)
{
NanEscapableScope();
Local<Array> a = NanNew<v8::Array>();
Nan::EscapableHandleScope scope;
Local<Array> a = Nan::New<v8::Array>();

for (changeset::iterator i = changes.begin(); i != changes.end(); i++) {
Local<Object> d = NanNew<v8::Object>();
d->Set(NanNew("what"), NanNew(i->first.c_str()));
d->Set(NanNew("size_bytes"), NanNew<v8::Number>(i->second.size));
d->Set(NanNew("size"), NanNew(mw_util::niceSize(i->second.size).c_str()));
d->Set(NanNew("+"), NanNew<v8::Number>(i->second.added));
d->Set(NanNew("-"), NanNew<v8::Number>(i->second.released));
Local<Object> d = Nan::New<v8::Object>();
d->Set(Nan::New("what").ToLocalChecked(), Nan::New(i->first.c_str()).ToLocalChecked());
d->Set(Nan::New("size_bytes").ToLocalChecked(), Nan::New<v8::Number>(i->second.size));
d->Set(Nan::New("size").ToLocalChecked(), Nan::New(mw_util::niceSize(i->second.size).c_str()).ToLocalChecked());
d->Set(Nan::New("+").ToLocalChecked(), Nan::New<v8::Number>(i->second.added));
d->Set(Nan::New("-").ToLocalChecked(), Nan::New<v8::Number>(i->second.released));
a->Set(a->Length(), d);
}

return NanEscapeScope(a);
return scope.Escape(a);
}


static v8::Handle<Value>
static v8::Local<Value>
compare(const v8::HeapSnapshot * before, const v8::HeapSnapshot * after)
{
NanEscapableScope();
Nan::EscapableHandleScope scope;
int s, diffBytes;

Local<Object> o = NanNew<v8::Object>();
Local<Object> o = Nan::New<v8::Object>();

// first let's append summary information
Local<Object> b = NanNew<v8::Object>();
b->Set(NanNew("nodes"), NanNew(before->GetNodesCount()));
//b->Set(NanNew("time"), s_startTime);
o->Set(NanNew("before"), b);
Local<Object> b = Nan::New<v8::Object>();
b->Set(Nan::New("nodes").ToLocalChecked(), Nan::New(before->GetNodesCount()));
//b->Set(Nan::New("time"), s_startTime);
o->Set(Nan::New("before").ToLocalChecked(), b);

Local<Object> a = NanNew<v8::Object>();
a->Set(NanNew("nodes"), NanNew(after->GetNodesCount()));
//a->Set(NanNew("time"), time(NULL));
o->Set(NanNew("after"), a);
Local<Object> a = Nan::New<v8::Object>();
a->Set(Nan::New("nodes").ToLocalChecked(), Nan::New(after->GetNodesCount()));
//a->Set(Nan::New("time"), time(NULL));
o->Set(Nan::New("after").ToLocalChecked(), a);

// now let's get allocations by name
set<uint64_t> beforeIDs, afterIDs;
s = 0;
buildIDSet(&beforeIDs, before->GetRoot(), s);
b->Set(NanNew("size_bytes"), NanNew(s));
b->Set(NanNew("size"), NanNew(mw_util::niceSize(s).c_str()));
b->Set(Nan::New("size_bytes").ToLocalChecked(), Nan::New(s));
b->Set(Nan::New("size").ToLocalChecked(), Nan::New(mw_util::niceSize(s).c_str()).ToLocalChecked());

diffBytes = s;
s = 0;
buildIDSet(&afterIDs, after->GetRoot(), s);
a->Set(NanNew("size_bytes"), NanNew(s));
a->Set(NanNew("size"), NanNew(mw_util::niceSize(s).c_str()));
a->Set(Nan::New("size_bytes").ToLocalChecked(), Nan::New(s));
a->Set(Nan::New("size").ToLocalChecked(), Nan::New(mw_util::niceSize(s).c_str()).ToLocalChecked());

diffBytes = s - diffBytes;

Local<Object> c = NanNew<v8::Object>();
c->Set(NanNew("size_bytes"), NanNew(diffBytes));
c->Set(NanNew("size"), NanNew(mw_util::niceSize(diffBytes).c_str()));
o->Set(NanNew("change"), c);
Local<Object> c = Nan::New<v8::Object>();
c->Set(Nan::New("size_bytes").ToLocalChecked(), Nan::New(diffBytes));
c->Set(Nan::New("size").ToLocalChecked(), Nan::New(mw_util::niceSize(diffBytes).c_str()).ToLocalChecked());
o->Set(Nan::New("change").ToLocalChecked(), c);

// before - after will reveal nodes released (memory freed)
vector<uint64_t> changedIDs;
setDiff(beforeIDs, afterIDs, changedIDs);
c->Set(NanNew("freed_nodes"), NanNew<v8::Number>(changedIDs.size()));
c->Set(Nan::New("freed_nodes").ToLocalChecked(), Nan::New<v8::Number>(changedIDs.size()));

// here's where we'll collect all the summary information
changeset changes;
Expand All @@ -286,48 +297,52 @@ compare(const v8::HeapSnapshot * before, const v8::HeapSnapshot * after)
// after - before will reveal nodes added (memory allocated)
setDiff(afterIDs, beforeIDs, changedIDs);

c->Set(NanNew("allocated_nodes"), NanNew<v8::Number>(changedIDs.size()));
c->Set(Nan::New("allocated_nodes").ToLocalChecked(), Nan::New<v8::Number>(changedIDs.size()));

for (unsigned long i = 0; i < changedIDs.size(); i++) {
const HeapGraphNode * n = after->GetNodeById(changedIDs[i]);
manageChange(changes, n, true);
}

c->Set(NanNew("details"), changesetToObject(changes));
c->Set(Nan::New("details").ToLocalChecked(), changesetToObject(changes));

return NanEscapeScope(o);
return scope.Escape(o);
}

NAN_METHOD(heapdiff::HeapDiff::End)
{
// take another snapshot and compare them
NanScope();
Nan::HandleScope scope;

HeapDiff *t = Unwrap<HeapDiff>( args.This() );
HeapDiff *t = Unwrap<HeapDiff>( info.This() );

// How shall we deal with double .end()ing? The only reasonable
// approach seems to be an exception, cause nothing else makes
// sense.
if (t->ended) {
return NanThrowError("attempt to end() a HeapDiff that was already ended");
return Nan::ThrowError("attempt to end() a HeapDiff that was already ended");
}
t->ended = true;

s_inProgress = true;
#if (NODE_MODULE_VERSION >= 0x002D)
t->after = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(NULL);
#else
#if (NODE_MODULE_VERSION > 0x000B)
t->after = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(NanNew<v8::String>(""), NULL);
t->after = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(Nan::New<v8::String>("").ToLocalChecked(), NULL);
#else
t->after = v8::HeapProfiler::TakeSnapshot(NanNew<v8::String>(""), HeapSnapshot::kFull, NULL);
t->after = v8::HeapProfiler::TakeSnapshot(Nan::New<v8::String>("").ToLocalChecked(), HeapSnapshot::kFull, NULL);
#endif
#endif
s_inProgress = false;

v8::Handle<Value> comparison = compare(t->before, t->after);
v8::Local<Value> comparison = compare(t->before, t->after);
// free early, free often. I mean, after all, this process we're in is
// probably having memory problems. We want to help her.
((HeapSnapshot *) t->before)->Delete();
t->before = NULL;
((HeapSnapshot *) t->after)->Delete();
t->after = NULL;

NanReturnValue(comparison);
info.GetReturnValue().Set(comparison);
}
2 changes: 1 addition & 1 deletion src/heapdiff.hh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace heapdiff
{
class HeapDiff : public node::ObjectWrap
class HeapDiff : public Nan::ObjectWrap
{
public:
static void Initialize ( v8::Handle<v8::Object> target );
Expand Down
Loading