Skip to content

Commit 35ec046

Browse files
SapMachine SAP#2250: Add adjustments to heap dumps for the buildpack (SAP#2251)
1 parent 2070a04 commit 35ec046

3 files changed

Lines changed: 378 additions & 5 deletions

File tree

src/hotspot/share/runtime/globals.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,39 @@ const int ObjectAlignmentInBytes = 8;
729729
"compression. Otherwise the level must be between 1 and 9.") \
730730
range(0, 9) \
731731
\
732+
/* SapMachine 2026-05-06: Allow to overwrite the heap dump file. */ \
733+
product(bool, HeapDumpOverwrite, false, MANAGEABLE, \
734+
"If enabled, the heap dump on out of memory error can " \
735+
"overwrite an already existing file.") \
736+
\
737+
/* SapMachine 2026-05-06: Sets the parallelism of the heap dump. */ \
738+
product(uint, HeapDumpParallelism, 0, MANAGEABLE, \
739+
"Sets the parallelism of the heap dump creation. 0 means to let "\
740+
"the VM decide.") \
741+
range(0, 100000) \
742+
\
743+
/* SapMachine 2026-05-06: Allow to skip content of arrays in dumps.*/ \
744+
product(bool, LimitPrimitiveArrayContentInHeapDump, false, MANAGEABLE, \
745+
"If enabled, the content of primitive arrays is not completely " \
746+
"written to a heap dump for large arrays. Note that this only " \
747+
"really saves space, if the compression of the heap dump is " \
748+
"enabled too, since the skipped elements are written as " \
749+
"0 or false.") \
750+
\
751+
/* SapMachine 2026-05-06: Allow to skip content of arrays in dumps.*/ \
752+
product(int, StringLikeContentSizeLimitInHeapDump, 120, MANAGEABLE, \
753+
"The number of entries in primitive char and byte arrays to " \
754+
"not skip in a heap dump when " \
755+
"LimitPrimitiveArrayContentInHeapDump is enabled.") \
756+
range(0, 100000) \
757+
\
758+
/* SapMachine 2026-05-06: Allow to skip contents of arrays in dumps.*/ \
759+
product(int, ArrayContentSizeLimitInHeapDump, 50, MANAGEABLE, \
760+
"The number of entries in a primitive array other than char and " \
761+
"byte arrays to not skip in a heap dump when " \
762+
"LimitPrimitiveArrayContentInHeapDump is enabled.") \
763+
range(0, 100000) \
764+
\
732765
product(ccstr, NativeMemoryTracking, DEBUG_ONLY("summary") NOT_DEBUG("off"), \
733766
"Native memory tracking options") \
734767
\

src/hotspot/share/services/heapDumper.cpp

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ class AbstractDumpWriter : public CHeapObj<mtInternal> {
441441
void write_symbolID(Symbol* o);
442442
void write_classID(Klass* k);
443443
void write_id(u4 x);
444+
// SapMachine 2026-05-06: Writes zeros to the buffer.
445+
void write_zero(size_t len);
444446

445447
// Start a new sub-record. Starts a new heap dump segment if needed.
446448
void start_sub_record(u1 tag, u4 len);
@@ -539,6 +541,26 @@ void AbstractDumpWriter::write_id(u4 x) {
539541
#endif
540542
}
541543

544+
// SapMachine 2026-05-06: Writes zeros to the buffer.
545+
void AbstractDumpWriter::write_zero(size_t len) {
546+
assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large");
547+
DEBUG_ONLY(_sub_record_left -= len);
548+
549+
// flush buffer to make room.
550+
while (len > buffer_size() - position()) {
551+
assert(!_in_dump_segment || _is_huge_sub_record,
552+
"Cannot overflow in non-huge sub-record.");
553+
size_t to_write = buffer_size() - position();
554+
memset(buffer() + position(), 0, to_write);
555+
len -= to_write;
556+
set_position(position() + to_write);
557+
flush();
558+
}
559+
560+
memset(buffer() + position(), 0, len);
561+
set_position(position() + len);
562+
}
563+
542564
// We use java mirror as the class ID
543565
void AbstractDumpWriter::write_classID(Klass* k) {
544566
write_objectID(k->java_mirror());
@@ -1372,6 +1394,24 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
13721394
return;
13731395
}
13741396

1397+
// SapMachine 2026-05-06: If enabled, we don't dump the whole content of large arrays, but just the start
1398+
// and fill the rest with zeroes.
1399+
int fill_with_zero = 0;
1400+
1401+
if (LimitPrimitiveArrayContentInHeapDump) {
1402+
int limit = ArrayContentSizeLimitInHeapDump;
1403+
1404+
if (type == T_BYTE || type == T_CHAR) {
1405+
limit = StringLikeContentSizeLimitInHeapDump;
1406+
}
1407+
1408+
if (length > limit) {
1409+
fill_with_zero = length - limit;
1410+
length = limit;
1411+
length_in_bytes = (u4) length * type_size;
1412+
}
1413+
}
1414+
13751415
// If the byte ordering is big endian then we can copy most types directly
13761416

13771417
switch (type) {
@@ -1439,6 +1479,11 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
14391479
default : ShouldNotReachHere();
14401480
}
14411481

1482+
// SapMachine 2026-05-06: Fill with zeros, if we don't dump the whole content of the array.
1483+
if (fill_with_zero > 0) {
1484+
writer->write_zero((u4) fill_with_zero * type_size);
1485+
}
1486+
14421487
writer->end_sub_record();
14431488
}
14441489

@@ -2433,7 +2478,8 @@ void VM_HeapDumper::doit() {
24332478

24342479
void VM_HeapDumper::work(uint worker_id) {
24352480
// VM Dumper works on all non-heap data dumping and part of heap iteration.
2436-
int dumper_id = get_next_dumper_id();
2481+
// SapMachine 2026-07-06: Don't create a segment for non-parallel dumps.
2482+
int dumper_id = is_parallel_dump() ? get_next_dumper_id() : VMDumperId;
24372483

24382484
if (is_vm_dumper(dumper_id)) {
24392485
// lock global writer, it will be unlocked after VM Dumper finishes with non-heap data
@@ -2475,8 +2521,11 @@ void VM_HeapDumper::work(uint worker_id) {
24752521

24762522
ResourceMark rm;
24772523
// share global compressor, local DumpWriter is not responsible for its life cycle
2478-
DumpWriter segment_writer(DumpMerger::get_writer_path(writer()->get_file_path(), dumper_id),
2479-
writer()->is_overwrite(), writer()->compressor());
2524+
// SapMachine 2026-05-06: Don't use segments if the dump is not parallel. This makes it
2525+
// possible to not use any disk space if dumping to a named pipe or a tty.
2526+
DumpWriter* parallel_writer = is_parallel_dump() ? new DumpWriter(DumpMerger::get_writer_path(writer()->get_file_path(), dumper_id),
2527+
writer()->is_overwrite(), writer()->compressor()) : nullptr;
2528+
DumpWriter& segment_writer = parallel_writer == nullptr ? *writer() : *parallel_writer;
24802529
if (!segment_writer.has_error()) {
24812530
if (is_vm_dumper(dumper_id)) {
24822531
// dump some non-heap subrecords to heap dump segment
@@ -2533,6 +2582,8 @@ void VM_HeapDumper::work(uint worker_id) {
25332582
// At this point, all fragments of the heapdump have been written to separate files.
25342583
// We need to merge them into a complete heapdump and write HPROF_HEAP_DUMP_END at that time.
25352584
}
2585+
// SapMachine 2026-05-06
2586+
delete parallel_writer;
25362587
}
25372588

25382589
void VM_HeapDumper::dump_stack_traces(AbstractDumpWriter* writer) {
@@ -2584,6 +2635,17 @@ void VM_HeapDumper::dump_vthread(oop vt, AbstractDumpWriter* segment_writer) {
25842635
ThreadDumper thread_dumper(ThreadDumper::ThreadType::UnmountedVirtual, nullptr, vt);
25852636
thread_dumper.init_serial_nums(&_thread_serial_num, &_frame_serial_num);
25862637

2638+
// SapMachine 2026-05-06: If we don't do a parallel dump, we don't need the lock
2639+
// but have to end the current heap dump segment.
2640+
if (!is_parallel_dump()) {
2641+
segment_writer->finish_dump_segment();
2642+
thread_dumper.dump_stack_traces(writer(), _klass_map);
2643+
thread_dumper.dump_thread_obj(segment_writer);
2644+
thread_dumper.dump_stack_refs(segment_writer);
2645+
2646+
return;
2647+
}
2648+
25872649
// write HPROF_TRACE/HPROF_FRAME records to global writer
25882650
_dumper_controller->lock_global_writer();
25892651
thread_dumper.dump_stack_traces(writer(), _klass_map);
@@ -2734,7 +2796,9 @@ void HeapDumper::set_error(char const* error) {
27342796
// outside of a JVM safepoint
27352797
void HeapDumper::dump_heap_from_oome() {
27362798
// SapMachine 2024-05-10: HeapDumpPath for jcmd
2737-
HeapDumper::dump_heap(false, true);
2799+
// SapMachine 2026-05-06: Handle HeapDumpOverwrite and HeapDumpParallelism.
2800+
HeapDumper::dump_heap(false, true, tty, -1, HeapDumpOverwrite, HeapDumpParallelism == 0 ?
2801+
HeapDumper::default_num_of_dump_threads(): HeapDumpParallelism);
27382802
}
27392803

27402804
// Called by error reporting by a single Java thread outside of a JVM safepoint,
@@ -2744,7 +2808,9 @@ void HeapDumper::dump_heap_from_oome() {
27442808
// inteference when updating the static variables base_path and dump_file_seq below.
27452809
void HeapDumper::dump_heap() {
27462810
// SapMachine 2024-05-10: HeapDumpPath for jcmd
2747-
HeapDumper::dump_heap(false, false);
2811+
// SapMachine 2026-05-06: Handle HeapDumpOverwrite and HeapDumpParallelism.
2812+
HeapDumper::dump_heap(false, false, tty, -1, HeapDumpOverwrite, HeapDumpParallelism == 0 ?
2813+
HeapDumper::default_num_of_dump_threads() : HeapDumpParallelism);
27482814
}
27492815

27502816
// SapMachine 2024-05-10: HeapDumpPath for jcmd

0 commit comments

Comments
 (0)