Skip to content

Commit 758e0a5

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Add option to write a heap snapshot on OOM.
TEST=ci Bug: #61036 Change-Id: I3f9ac67179ba54453f18695853afa78501d587a5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439344 Reviewed-by: Alexander Aprelev <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent c8c58aa commit 758e0a5

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import "dart:io";
6+
import "package:expect/expect.dart";
7+
import "use_flag_test_helper.dart";
8+
9+
main(List<String> arguments) async {
10+
if (arguments.contains("--testee")) {
11+
var x = [];
12+
while (true) {
13+
x = [x];
14+
}
15+
return;
16+
}
17+
18+
// Snapshot write omitted from product mode.
19+
if (const bool.fromEnvironment("dart.vm.product")) return;
20+
21+
await withTempDir("heap_snapshot_on_oom_test", (String dir) async {
22+
var exec = Platform.executable;
23+
var args = [
24+
...Platform.executableArguments,
25+
"--heap_snapshot_on_oom=$dir/oom.heapsnapshot",
26+
"--old_gen_heap_size=50", // MB
27+
Platform.script.toFilePath(),
28+
"--testee",
29+
];
30+
print("+ $exec ${args.join(' ')}");
31+
32+
var result = Process.runSync(exec, args);
33+
print("Command stdout:");
34+
print(result.stdout);
35+
print("Command stderr:");
36+
print(result.stderr);
37+
38+
Expect.equals(255, result.exitCode);
39+
Expect.contains("Out of Memory", result.stderr);
40+
41+
Expect.isTrue(await File("$dir/oom.heapsnapshot").exists());
42+
Expect.isTrue(await File("$dir/oom.heapsnapshot").length() > 0);
43+
});
44+
}

runtime/vm/heap/heap.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "vm/isolate.h"
2222
#include "vm/lockers.h"
2323
#include "vm/object.h"
24+
#include "vm/object_graph.h"
2425
#include "vm/object_set.h"
2526
#include "vm/os.h"
2627
#include "vm/raw_object.h"
@@ -40,6 +41,13 @@ DEFINE_FLAG(bool,
4041
disable_heap_verification,
4142
false,
4243
"Explicitly disable heap verification.");
44+
#if defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
45+
DEFINE_FLAG(charp,
46+
heap_snapshot_on_oom,
47+
nullptr,
48+
"Write a heap snapshot after encountering an Out of Memory error. "
49+
"Best used with a reduced --old_gen_heap_size");
50+
#endif
4351

4452
Heap::Heap(IsolateGroup* isolate_group,
4553
bool is_vm_isolate,
@@ -184,6 +192,20 @@ uword Heap::AllocateOld(Thread* thread, intptr_t size, bool is_exec) {
184192
OS::PrintErr("Exhausted heap space, trying to allocate %" Pd " bytes.\n",
185193
size);
186194
isolate_group_->set_has_seen_oom(true);
195+
#if defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
196+
if (FLAG_heap_snapshot_on_oom != nullptr) {
197+
bool successful = false;
198+
{
199+
FileHeapSnapshotWriter file_writer(thread, FLAG_heap_snapshot_on_oom,
200+
&successful);
201+
HeapSnapshotWriter writer(thread, &file_writer);
202+
writer.Write();
203+
}
204+
if (!successful) {
205+
OS::PrintErr("Failed to write heapsnapshot\n");
206+
}
207+
}
208+
#endif
187209
return 0;
188210
}
189211

0 commit comments

Comments
 (0)