Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5f57005

Browse filesBrowse files
bripkenscjihrig
authored andcommitted
v8,src: expose statistics about heap spaces
Provide means to inspect information about the separate heap spaces via a callable API. This is helpful to analyze memory issues. Fixes: #2079 PR-URL: #4463 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent e65f1f7 commit 5f57005
Copy full SHA for 5f57005

File tree

Expand file treeCollapse file tree

6 files changed

+202
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+202
-2
lines changed
Open diff view settings
Collapse file

‎doc/api/v8.markdown‎

Copy file name to clipboardExpand all lines: doc/api/v8.markdown
+49Lines changed: 49 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,55 @@ Returns an object with the following properties
2121
}
2222
```
2323

24+
## getHeapSpaceStatistics()
25+
26+
Returns statistics about the V8 heap spaces, i.e. the segments which make up
27+
the V8 heap. Order of heap spaces nor availability of a heap space can be
28+
guaranteed as the statistics are provided via the V8 `GetHeapSpaceStatistics`
29+
function.
30+
31+
Example result:
32+
33+
```
34+
[
35+
{
36+
"space_name": "new_space",
37+
"space_size": 2063872,
38+
"space_used_size": 951112,
39+
"space_available_size": 80824,
40+
"physical_space_size": 2063872
41+
},
42+
{
43+
"space_name": "old_space",
44+
"space_size": 3090560,
45+
"space_used_size": 2493792,
46+
"space_available_size": 0,
47+
"physical_space_size": 3090560
48+
},
49+
{
50+
"space_name": "code_space",
51+
"space_size": 1260160,
52+
"space_used_size": 644256,
53+
"space_available_size": 960,
54+
"physical_space_size": 1260160
55+
},
56+
{
57+
"space_name": "map_space",
58+
"space_size": 1094160,
59+
"space_used_size": 201608,
60+
"space_available_size": 0,
61+
"physical_space_size": 1094160
62+
},
63+
{
64+
"space_name": "large_object_space",
65+
"space_size": 0,
66+
"space_used_size": 0,
67+
"space_available_size": 1490980608,
68+
"physical_space_size": 0
69+
}
70+
]
71+
```
72+
2473
## setFlagsFromString(string)
2574

2675
Set additional V8 command line flags. Use with care; changing settings
Collapse file

‎lib/v8.js‎

Copy file name to clipboardExpand all lines: lib/v8.js
+32-1Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,28 @@
1616

1717
const v8binding = process.binding('v8');
1818

19+
// Properties for heap statistics buffer extraction.
1920
const heapStatisticsBuffer =
2021
new Uint32Array(v8binding.heapStatisticsArrayBuffer);
21-
2222
const kTotalHeapSizeIndex = v8binding.kTotalHeapSizeIndex;
2323
const kTotalHeapSizeExecutableIndex = v8binding.kTotalHeapSizeExecutableIndex;
2424
const kTotalPhysicalSizeIndex = v8binding.kTotalPhysicalSizeIndex;
2525
const kTotalAvailableSize = v8binding.kTotalAvailableSize;
2626
const kUsedHeapSizeIndex = v8binding.kUsedHeapSizeIndex;
2727
const kHeapSizeLimitIndex = v8binding.kHeapSizeLimitIndex;
2828

29+
// Properties for heap space statistics buffer extraction.
30+
const heapSpaceStatisticsBuffer =
31+
new Uint32Array(v8binding.heapSpaceStatisticsArrayBuffer);
32+
const kHeapSpaces = v8binding.kHeapSpaces;
33+
const kNumberOfHeapSpaces = kHeapSpaces.length;
34+
const kHeapSpaceStatisticsPropertiesCount =
35+
v8binding.kHeapSpaceStatisticsPropertiesCount;
36+
const kSpaceSizeIndex = v8binding.kSpaceSizeIndex;
37+
const kSpaceUsedSizeIndex = v8binding.kSpaceUsedSizeIndex;
38+
const kSpaceAvailableSizeIndex = v8binding.kSpaceAvailableSizeIndex;
39+
const kPhysicalSpaceSizeIndex = v8binding.kPhysicalSpaceSizeIndex;
40+
2941
exports.getHeapStatistics = function() {
3042
const buffer = heapStatisticsBuffer;
3143

@@ -42,3 +54,22 @@ exports.getHeapStatistics = function() {
4254
};
4355

4456
exports.setFlagsFromString = v8binding.setFlagsFromString;
57+
58+
exports.getHeapSpaceStatistics = function() {
59+
const heapSpaceStatistics = new Array(kNumberOfHeapSpaces);
60+
const buffer = heapSpaceStatisticsBuffer;
61+
v8binding.updateHeapSpaceStatisticsArrayBuffer();
62+
63+
for (let i = 0; i < kNumberOfHeapSpaces; i++) {
64+
const propertyOffset = i * kHeapSpaceStatisticsPropertiesCount;
65+
heapSpaceStatistics[i] = {
66+
space_name: kHeapSpaces[i],
67+
space_size: buffer[propertyOffset + kSpaceSizeIndex],
68+
space_used_size: buffer[propertyOffset + kSpaceUsedSizeIndex],
69+
space_available_size: buffer[propertyOffset + kSpaceAvailableSizeIndex],
70+
physical_space_size: buffer[propertyOffset + kPhysicalSpaceSizeIndex]
71+
};
72+
}
73+
74+
return heapSpaceStatistics;
75+
};
Collapse file

‎src/env-inl.h‎

Copy file name to clipboardExpand all lines: src/env-inl.h
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ inline Environment::~Environment() {
242242
isolate_data()->Put();
243243

244244
delete[] heap_statistics_buffer_;
245+
delete[] heap_space_statistics_buffer_;
245246
delete[] http_parser_buffer_;
246247
}
247248

@@ -374,6 +375,17 @@ inline void Environment::set_heap_statistics_buffer(uint32_t* pointer) {
374375
heap_statistics_buffer_ = pointer;
375376
}
376377

378+
inline uint32_t* Environment::heap_space_statistics_buffer() const {
379+
CHECK_NE(heap_space_statistics_buffer_, nullptr);
380+
return heap_space_statistics_buffer_;
381+
}
382+
383+
inline void Environment::set_heap_space_statistics_buffer(uint32_t* pointer) {
384+
CHECK_EQ(heap_space_statistics_buffer_, nullptr); // Should be set only once.
385+
heap_space_statistics_buffer_ = pointer;
386+
}
387+
388+
377389
inline char* Environment::http_parser_buffer() const {
378390
return http_parser_buffer_;
379391
}
Collapse file

‎src/env.h‎

Copy file name to clipboardExpand all lines: src/env.h
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,9 @@ class Environment {
462462
inline uint32_t* heap_statistics_buffer() const;
463463
inline void set_heap_statistics_buffer(uint32_t* pointer);
464464

465+
inline uint32_t* heap_space_statistics_buffer() const;
466+
inline void set_heap_space_statistics_buffer(uint32_t* pointer);
467+
465468
inline char* http_parser_buffer() const;
466469
inline void set_http_parser_buffer(char* buffer);
467470

@@ -562,6 +565,7 @@ class Environment {
562565
int handle_cleanup_waiting_;
563566

564567
uint32_t* heap_statistics_buffer_ = nullptr;
568+
uint32_t* heap_space_statistics_buffer_ = nullptr;
565569

566570
char* http_parser_buffer_;
567571

Collapse file

‎src/node_v8.cc‎

Copy file name to clipboardExpand all lines: src/node_v8.cc
+86-1Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
namespace node {
99

10+
using v8::Array;
1011
using v8::ArrayBuffer;
1112
using v8::Context;
1213
using v8::Function;
1314
using v8::FunctionCallbackInfo;
15+
using v8::HeapSpaceStatistics;
1416
using v8::HeapStatistics;
1517
using v8::Isolate;
1618
using v8::Local;
19+
using v8::NewStringType;
1720
using v8::Object;
1821
using v8::String;
1922
using v8::Uint32;
@@ -34,6 +37,21 @@ static const size_t kHeapStatisticsPropertiesCount =
3437
HEAP_STATISTICS_PROPERTIES(V);
3538
#undef V
3639

40+
#define HEAP_SPACE_STATISTICS_PROPERTIES(V) \
41+
V(0, space_size, kSpaceSizeIndex) \
42+
V(1, space_used_size, kSpaceUsedSizeIndex) \
43+
V(2, space_available_size, kSpaceAvailableSizeIndex) \
44+
V(3, physical_space_size, kPhysicalSpaceSizeIndex)
45+
46+
#define V(a, b, c) +1
47+
static const size_t kHeapSpaceStatisticsPropertiesCount =
48+
HEAP_SPACE_STATISTICS_PROPERTIES(V);
49+
#undef V
50+
51+
// Will be populated in InitializeV8Bindings.
52+
static size_t number_of_heap_spaces = 0;
53+
54+
3755
void UpdateHeapStatisticsArrayBuffer(const FunctionCallbackInfo<Value>& args) {
3856
Environment* env = Environment::GetCurrent(args);
3957
HeapStatistics s;
@@ -45,6 +63,23 @@ void UpdateHeapStatisticsArrayBuffer(const FunctionCallbackInfo<Value>& args) {
4563
}
4664

4765

66+
void UpdateHeapSpaceStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
67+
Environment* env = Environment::GetCurrent(args);
68+
HeapSpaceStatistics s;
69+
Isolate* const isolate = env->isolate();
70+
uint32_t* buffer = env->heap_space_statistics_buffer();
71+
72+
for (size_t i = 0; i < number_of_heap_spaces; i++) {
73+
isolate->GetHeapSpaceStatistics(&s, i);
74+
size_t const property_offset = i * kHeapSpaceStatisticsPropertiesCount;
75+
#define V(index, name, _) buffer[property_offset + index] = \
76+
static_cast<uint32_t>(s.name());
77+
HEAP_SPACE_STATISTICS_PROPERTIES(V)
78+
#undef V
79+
}
80+
}
81+
82+
4883
void SetFlagsFromString(const FunctionCallbackInfo<Value>& args) {
4984
Environment* env = Environment::GetCurrent(args);
5085

@@ -62,10 +97,10 @@ void InitializeV8Bindings(Local<Object> target,
6297
Local<Value> unused,
6398
Local<Context> context) {
6499
Environment* env = Environment::GetCurrent(context);
100+
65101
env->SetMethod(target,
66102
"updateHeapStatisticsArrayBuffer",
67103
UpdateHeapStatisticsArrayBuffer);
68-
env->SetMethod(target, "setFlagsFromString", SetFlagsFromString);
69104

70105
env->set_heap_statistics_buffer(new uint32_t[kHeapStatisticsPropertiesCount]);
71106

@@ -84,6 +119,56 @@ void InitializeV8Bindings(Local<Object> target,
84119

85120
HEAP_STATISTICS_PROPERTIES(V)
86121
#undef V
122+
123+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
124+
"kHeapSpaceStatisticsPropertiesCount"),
125+
Uint32::NewFromUnsigned(env->isolate(),
126+
kHeapSpaceStatisticsPropertiesCount));
127+
128+
number_of_heap_spaces = env->isolate()->NumberOfHeapSpaces();
129+
130+
// Heap space names are extracted once and exposed to JavaScript to
131+
// avoid excessive creation of heap space name Strings.
132+
HeapSpaceStatistics s;
133+
const Local<Array> heap_spaces = Array::New(env->isolate(),
134+
number_of_heap_spaces);
135+
for (size_t i = 0; i < number_of_heap_spaces; i++) {
136+
env->isolate()->GetHeapSpaceStatistics(&s, i);
137+
Local<String> heap_space_name = String::NewFromUtf8(env->isolate(),
138+
s.space_name(),
139+
NewStringType::kNormal)
140+
.ToLocalChecked();
141+
heap_spaces->Set(i, heap_space_name);
142+
}
143+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kHeapSpaces"),
144+
heap_spaces);
145+
146+
env->SetMethod(target,
147+
"updateHeapSpaceStatisticsArrayBuffer",
148+
UpdateHeapSpaceStatisticsBuffer);
149+
150+
env->set_heap_space_statistics_buffer(
151+
new uint32_t[kHeapSpaceStatisticsPropertiesCount * number_of_heap_spaces]);
152+
153+
const size_t heap_space_statistics_buffer_byte_length =
154+
sizeof(*env->heap_space_statistics_buffer()) *
155+
kHeapSpaceStatisticsPropertiesCount *
156+
number_of_heap_spaces;
157+
158+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
159+
"heapSpaceStatisticsArrayBuffer"),
160+
ArrayBuffer::New(env->isolate(),
161+
env->heap_space_statistics_buffer(),
162+
heap_space_statistics_buffer_byte_length));
163+
164+
#define V(i, _, name) \
165+
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #name), \
166+
Uint32::NewFromUnsigned(env->isolate(), i));
167+
168+
HEAP_SPACE_STATISTICS_PROPERTIES(V)
169+
#undef V
170+
171+
env->SetMethod(target, "setFlagsFromString", SetFlagsFromString);
87172
}
88173

89174
} // namespace node
Collapse file

‎test/parallel/test-v8-stats.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-v8-stats.js
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,22 @@ assert.deepEqual(Object.keys(s).sort(), keys);
1515
keys.forEach(function(key) {
1616
assert.equal(typeof s[key], 'number');
1717
});
18+
19+
20+
const expectedHeapSpaces = [
21+
'new_space',
22+
'old_space',
23+
'code_space',
24+
'map_space',
25+
'large_object_space'
26+
];
27+
const heapSpaceStatistics = v8.getHeapSpaceStatistics();
28+
const actualHeapSpaceNames = heapSpaceStatistics.map(s => s.space_name);
29+
assert.deepEqual(actualHeapSpaceNames.sort(), expectedHeapSpaces.sort());
30+
heapSpaceStatistics.forEach(heapSpace => {
31+
assert.strictEqual(typeof heapSpace.space_name, 'string');
32+
assert.strictEqual(typeof heapSpace.space_size, 'number');
33+
assert.strictEqual(typeof heapSpace.space_used_size, 'number');
34+
assert.strictEqual(typeof heapSpace.space_available_size, 'number');
35+
assert.strictEqual(typeof heapSpace.physical_space_size, 'number');
36+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.