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 30d60cf

Browse filesBrowse files
bripkensMylesBorins
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 4e07bd4 commit 30d60cf
Copy full SHA for 30d60cf

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.md‎

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

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

@@ -387,6 +388,17 @@ inline void Environment::set_heap_statistics_buffer(uint32_t* pointer) {
387388
heap_statistics_buffer_ = pointer;
388389
}
389390

391+
inline uint32_t* Environment::heap_space_statistics_buffer() const {
392+
CHECK_NE(heap_space_statistics_buffer_, nullptr);
393+
return heap_space_statistics_buffer_;
394+
}
395+
396+
inline void Environment::set_heap_space_statistics_buffer(uint32_t* pointer) {
397+
CHECK_EQ(heap_space_statistics_buffer_, nullptr); // Should be set only once.
398+
heap_space_statistics_buffer_ = pointer;
399+
}
400+
401+
390402
inline char* Environment::http_parser_buffer() const {
391403
return http_parser_buffer_;
392404
}
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
@@ -460,6 +460,9 @@ class Environment {
460460
inline uint32_t* heap_statistics_buffer() const;
461461
inline void set_heap_statistics_buffer(uint32_t* pointer);
462462

463+
inline uint32_t* heap_space_statistics_buffer() const;
464+
inline void set_heap_space_statistics_buffer(uint32_t* pointer);
465+
463466
inline char* http_parser_buffer() const;
464467
inline void set_http_parser_buffer(char* buffer);
465468

@@ -563,6 +566,7 @@ class Environment {
563566
int handle_cleanup_waiting_;
564567

565568
uint32_t* heap_statistics_buffer_ = nullptr;
569+
uint32_t* heap_space_statistics_buffer_ = nullptr;
566570

567571
char* http_parser_buffer_;
568572

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.