Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
32 changes: 32 additions & 0 deletions src/hotspot/share/runtime/globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,38 @@ const int ObjectAlignmentInBytes = 8;
"compression. Otherwise the level must be between 1 and 9.") \
range(0, 9) \
\
/* SapMachine 2026-05-06: Allow to overwrite the heap dump file. */ \
product(bool, HeapDumpOverwrite, false, MANAGEABLE, \
"If enabled, the heap dump on out of memory error can " \
"overwrite an already existing file.") \
\
/* SapMachine 2026-05-06: Sets the parallelism of the heap dump. */ \
product(uint, HeapDumpParallelism, 0, MANAGEABLE, \
"Sets the parallelism of the heap dump creation. 0 means to let "\
"the VM decide.") \
\
/* SAPJVM 2026-05-06: Allow to skip content of large arrays in dumps.*/ \
Comment thread
schmelter-sap marked this conversation as resolved.
Outdated
product(bool, LimitPrimArrayContentInHeapDump, false, MANAGEABLE, \
Comment thread
schmelter-sap marked this conversation as resolved.
Outdated
"If enabled, the content of primitive arrays in not completely " \
"written to a heap dump for large arrays. Note that this only " \
"really safes space, if the compression of the heap dump is " \
"enabled too, since the skipped elements are written as " \
"0 or false.") \
\
/* SAPJVM 2026-05-06: Allow to skip content of large arrays in dumps.*/ \
product(int, StringLikeContentSizeLimitInHeapDump, 120, MANAGEABLE, \
"The number of entries in primitive char and bytes arrays to " \
"not skip in a heap dump when LimitPrimArrayContentInHeapDump " \
"is enabled.") \
range(0, 100000) \
\
/* SAPJVM 2026-05-06: Allow to skip content of large arrays in dumps.*/ \
product(int, ArrayContentSizeLimitInHeapDump, 50, MANAGEABLE, \
"The number of entries in a primitive array other than char and " \
"byte arrays to not skip in a heap dump when " \
"LimitPrimArrayContentInHeapDump is enabled.") \
range(0, 100000) \
\
Comment thread
schmelter-sap marked this conversation as resolved.
product(ccstr, NativeMemoryTracking, DEBUG_ONLY("summary") NOT_DEBUG("off"), \
"Native memory tracking options") \
\
Expand Down
77 changes: 73 additions & 4 deletions src/hotspot/share/services/heapDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ class AbstractDumpWriter : public CHeapObj<mtInternal> {
void write_symbolID(Symbol* o);
void write_classID(Klass* k);
void write_id(u4 x);
// SAPJVM 2026-05-06: Writes zeros to the buffer.
void write_zero(size_t len);

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

// SAPJVM 2026-05-06: Writes zeros to the buffer.
void AbstractDumpWriter::write_zero(size_t len) {
assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large");
DEBUG_ONLY(_sub_record_left -= len);

// flush buffer to make room.
while (len > buffer_size() - position()) {
assert(!_in_dump_segment || _is_huge_sub_record,
"Cannot overflow in non-huge sub-record.");
size_t to_write = buffer_size() - position();
memset(buffer() + position(), 0, to_write);
len -= to_write;
set_position(position() + to_write);
flush();
}

memset(buffer() + position(), 0, len);
set_position(position() + len);
}

// We use java mirror as the class ID
void AbstractDumpWriter::write_classID(Klass* k) {
write_objectID(k->java_mirror());
Expand Down Expand Up @@ -1357,6 +1379,8 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr

int length = calculate_array_max_length(writer, array, header_size);
int type_size = type2aelembytes(type);
// SapMachine 2026-05-06
int fill_with_zero = 0;
Comment thread
schmelter-sap marked this conversation as resolved.
Outdated
u4 length_in_bytes = (u4)length * type_size;
u4 size = header_size + length_in_bytes;

Expand All @@ -1372,6 +1396,21 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
return;
}

// SAPJVM 2026-05-06: If enabled, we don't dump the whole content of large arrays, but just the start.
Comment thread
schmelter-sap marked this conversation as resolved.
Outdated
if (LimitPrimArrayContentInHeapDump) {
int limit = ArrayContentSizeLimitInHeapDump;

if (type == T_BYTE || type == T_CHAR) {
limit = StringLikeContentSizeLimitInHeapDump;
}

if (length > limit) {
fill_with_zero = length - limit;
length = limit;
length_in_bytes = (u4) length * type_size;
}
}

// If the byte ordering is big endian then we can copy most types directly

switch (type) {
Expand Down Expand Up @@ -1439,6 +1478,11 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
default : ShouldNotReachHere();
}

// SAPJVM 2026-05-06: Fill with zeros, if we don't dump the whole content of the array.
if (fill_with_zero > 0) {
writer->write_zero((u4) fill_with_zero * type_size);
Comment thread
schmelter-sap marked this conversation as resolved.
}

writer->end_sub_record();
}

Expand Down Expand Up @@ -2200,6 +2244,11 @@ void DumpMerger::merge_file(const char* path) {
#endif

void DumpMerger::do_merge() {
// SapMachine 2026-05-06: No need to merge a non-parallel heap dump.
if (_dump_seq <= 1) {
return;
}

TraceTime timer("Merge heap files complete", TRACETIME_LOG(Info, heapdump));

// Since contents in segmented heap file were already zipped, we don't need to zip
Expand Down Expand Up @@ -2475,8 +2524,11 @@ void VM_HeapDumper::work(uint worker_id) {

ResourceMark rm;
// share global compressor, local DumpWriter is not responsible for its life cycle
DumpWriter segment_writer(DumpMerger::get_writer_path(writer()->get_file_path(), dumper_id),
writer()->is_overwrite(), writer()->compressor());
// SapMachine 2026-05-06: Don't use segments if the dump is not parallel. This makes it
// possible to not use any disk space if dumping to a names pipe or a tty.
Comment thread
RealCLanger marked this conversation as resolved.
Outdated
DumpWriter* parallel_writer = is_parallel_dump() ? new DumpWriter(DumpMerger::get_writer_path(writer()->get_file_path(), dumper_id),
writer()->is_overwrite(), writer()->compressor()) : nullptr;
DumpWriter& segment_writer = parallel_writer == nullptr ? *writer() : *parallel_writer;
if (!segment_writer.has_error()) {
if (is_vm_dumper(dumper_id)) {
// dump some non-heap subrecords to heap dump segment
Expand Down Expand Up @@ -2533,6 +2585,8 @@ void VM_HeapDumper::work(uint worker_id) {
// At this point, all fragments of the heapdump have been written to separate files.
// We need to merge them into a complete heapdump and write HPROF_HEAP_DUMP_END at that time.
}
// SapMachine 2026-05-06
delete parallel_writer;
}

void VM_HeapDumper::dump_stack_traces(AbstractDumpWriter* writer) {
Expand Down Expand Up @@ -2584,6 +2638,17 @@ void VM_HeapDumper::dump_vthread(oop vt, AbstractDumpWriter* segment_writer) {
ThreadDumper thread_dumper(ThreadDumper::ThreadType::UnmountedVirtual, nullptr, vt);
thread_dumper.init_serial_nums(&_thread_serial_num, &_frame_serial_num);

// SapMachine 2026-05-06: If we don't do a parallel dump, we don't need the lock
// but have to end the current heap dump segment.
if (!is_parallel_dump()) {
segment_writer->finish_dump_segment();
thread_dumper.dump_stack_traces(writer(), _klass_map);
thread_dumper.dump_thread_obj(segment_writer);
thread_dumper.dump_stack_refs(segment_writer);

return;
}

// write HPROF_TRACE/HPROF_FRAME records to global writer
_dumper_controller->lock_global_writer();
thread_dumper.dump_stack_traces(writer(), _klass_map);
Expand Down Expand Up @@ -2734,7 +2799,9 @@ void HeapDumper::set_error(char const* error) {
// outside of a JVM safepoint
void HeapDumper::dump_heap_from_oome() {
// SapMachine 2024-05-10: HeapDumpPath for jcmd
HeapDumper::dump_heap(false, true);
// SapMachine 2026-05-06: Handle HeapDumpOverwrite and HeapDumpParallelism.
HeapDumper::dump_heap(false, true, tty, -1, HeapDumpOverwrite, HeapDumpParallelism == 0 ?
HeapDumper::default_num_of_dump_threads(): HeapDumpParallelism);
}

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

// SapMachine 2024-05-10: HeapDumpPath for jcmd
Expand Down
Loading
Loading