8283474: Include detailed heap object info in CDS map file
Reviewed-by: ccheung, stuefe
This commit is contained in:
parent
060a188733
commit
c1e67b6603
src/hotspot/share/cds
@ -27,6 +27,7 @@
|
||||
#include "cds/archiveUtils.hpp"
|
||||
#include "cds/cppVtables.hpp"
|
||||
#include "cds/dumpAllocStats.hpp"
|
||||
#include "cds/heapShared.hpp"
|
||||
#include "cds/metaspaceShared.hpp"
|
||||
#include "classfile/classLoaderDataShared.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
@ -40,6 +41,7 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oopHandle.inline.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
@ -929,27 +931,29 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
}
|
||||
|
||||
// rw/ro regions only
|
||||
static void write_dump_region(const char* name, DumpRegion* region) {
|
||||
static void log_metaspace_region(const char* name, DumpRegion* region,
|
||||
const ArchiveBuilder::SourceObjList* src_objs) {
|
||||
address region_base = address(region->base());
|
||||
address region_top = address(region->top());
|
||||
write_region(name, region_base, region_top, region_base + buffer_to_runtime_delta());
|
||||
log_region(name, region_base, region_top, region_base + buffer_to_runtime_delta());
|
||||
log_metaspace_objects(region, src_objs);
|
||||
}
|
||||
|
||||
#define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d"
|
||||
|
||||
static void write_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* current) {
|
||||
static void log_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* current) {
|
||||
ResourceMark rm(current);
|
||||
log_debug(cds, map)(_LOG_PREFIX " %s",
|
||||
p2i(runtime_dest), type_name, bytes, k->external_name());
|
||||
}
|
||||
static void write_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* current) {
|
||||
static void log_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* current) {
|
||||
ResourceMark rm(current);
|
||||
log_debug(cds, map)(_LOG_PREFIX " %s",
|
||||
p2i(runtime_dest), type_name, bytes, m->external_name());
|
||||
}
|
||||
|
||||
// rw/ro regions only
|
||||
static void write_objects(DumpRegion* region, const ArchiveBuilder::SourceObjList* src_objs) {
|
||||
static void log_metaspace_objects(DumpRegion* region, const ArchiveBuilder::SourceObjList* src_objs) {
|
||||
address last_obj_base = address(region->base());
|
||||
address last_obj_end = address(region->base());
|
||||
address region_end = address(region->end());
|
||||
@ -958,7 +962,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
SourceObjInfo* src_info = src_objs->at(i);
|
||||
address src = src_info->orig_obj();
|
||||
address dest = src_info->dumped_addr();
|
||||
write_data(last_obj_base, dest, last_obj_base + buffer_to_runtime_delta());
|
||||
log_data(last_obj_base, dest, last_obj_base + buffer_to_runtime_delta());
|
||||
address runtime_dest = dest + buffer_to_runtime_delta();
|
||||
int bytes = src_info->size_in_bytes();
|
||||
|
||||
@ -967,21 +971,21 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
|
||||
switch (type) {
|
||||
case MetaspaceObj::ClassType:
|
||||
write_klass((Klass*)src, runtime_dest, type_name, bytes, current);
|
||||
log_klass((Klass*)src, runtime_dest, type_name, bytes, current);
|
||||
break;
|
||||
case MetaspaceObj::ConstantPoolType:
|
||||
write_klass(((ConstantPool*)src)->pool_holder(),
|
||||
log_klass(((ConstantPool*)src)->pool_holder(),
|
||||
runtime_dest, type_name, bytes, current);
|
||||
break;
|
||||
case MetaspaceObj::ConstantPoolCacheType:
|
||||
write_klass(((ConstantPoolCache*)src)->constant_pool()->pool_holder(),
|
||||
log_klass(((ConstantPoolCache*)src)->constant_pool()->pool_holder(),
|
||||
runtime_dest, type_name, bytes, current);
|
||||
break;
|
||||
case MetaspaceObj::MethodType:
|
||||
write_method((Method*)src, runtime_dest, type_name, bytes, current);
|
||||
log_method((Method*)src, runtime_dest, type_name, bytes, current);
|
||||
break;
|
||||
case MetaspaceObj::ConstMethodType:
|
||||
write_method(((ConstMethod*)src)->method(), runtime_dest, type_name, bytes, current);
|
||||
log_method(((ConstMethod*)src)->method(), runtime_dest, type_name, bytes, current);
|
||||
break;
|
||||
case MetaspaceObj::SymbolType:
|
||||
{
|
||||
@ -1000,22 +1004,22 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
last_obj_end = dest + bytes;
|
||||
}
|
||||
|
||||
write_data(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta());
|
||||
log_data(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta());
|
||||
if (last_obj_end < region_end) {
|
||||
log_debug(cds, map)(PTR_FORMAT ": @@ Misc data " SIZE_FORMAT " bytes",
|
||||
p2i(last_obj_end + buffer_to_runtime_delta()),
|
||||
size_t(region_end - last_obj_end));
|
||||
write_data(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta());
|
||||
log_data(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta());
|
||||
}
|
||||
}
|
||||
|
||||
#undef _LOG_PREFIX
|
||||
|
||||
// Write information about a region, whose address at dump time is [base .. top). At
|
||||
// Log information about a region, whose address at dump time is [base .. top). At
|
||||
// runtime, this region will be mapped to runtime_base. runtime_base is 0 if this
|
||||
// region will be mapped at os-selected addresses (such as the bitmap region), or will
|
||||
// be accessed with os::read (the header).
|
||||
static void write_region(const char* name, address base, address top, address runtime_base) {
|
||||
static void log_region(const char* name, address base, address top, address runtime_base) {
|
||||
size_t size = top - base;
|
||||
base = runtime_base;
|
||||
top = runtime_base + size;
|
||||
@ -1024,27 +1028,63 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
}
|
||||
|
||||
// open and closed archive regions
|
||||
static void write_heap_region(const char* which, GrowableArray<MemRegion> *regions) {
|
||||
static void log_heap_regions(const char* which, GrowableArray<MemRegion> *regions) {
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
for (int i = 0; i < regions->length(); i++) {
|
||||
address start = address(regions->at(i).start());
|
||||
address end = address(regions->at(i).end());
|
||||
write_region(which, start, end, start);
|
||||
write_data(start, end, start);
|
||||
log_region(which, start, end, start);
|
||||
|
||||
while (start < end) {
|
||||
size_t byte_size;
|
||||
oop archived_oop = cast_to_oop(start);
|
||||
oop original_oop = HeapShared::get_original_object(archived_oop);
|
||||
if (original_oop != NULL) {
|
||||
ResourceMark rm;
|
||||
log_info(cds, map)(PTR_FORMAT ": @@ Object %s",
|
||||
p2i(start), original_oop->klass()->external_name());
|
||||
byte_size = original_oop->size() * BytesPerWord;
|
||||
} else if (archived_oop == HeapShared::roots()) {
|
||||
// HeapShared::roots() is copied specially so it doesn't exist in
|
||||
// HeapShared::OriginalObjectTable. See HeapShared::copy_roots().
|
||||
log_info(cds, map)(PTR_FORMAT ": @@ Object HeapShared:roots (ObjArray)",
|
||||
p2i(start));
|
||||
byte_size = objArrayOopDesc::object_size(HeapShared::roots()->length()) * BytesPerWord;
|
||||
} else {
|
||||
// We have reached the end of the region
|
||||
break;
|
||||
}
|
||||
address oop_end = start + byte_size;
|
||||
log_data(start, oop_end, start, /*is_heap=*/true);
|
||||
start = oop_end;
|
||||
}
|
||||
if (start < end) {
|
||||
log_info(cds, map)(PTR_FORMAT ": @@ Unused heap space " SIZE_FORMAT " bytes",
|
||||
p2i(start), size_t(end - start));
|
||||
log_data(start, end, start, /*is_heap=*/true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Dump all the data [base...top). Pretend that the base address
|
||||
// Log all the data [base...top). Pretend that the base address
|
||||
// will be mapped to runtime_base at run-time.
|
||||
static void write_data(address base, address top, address runtime_base) {
|
||||
static void log_data(address base, address top, address runtime_base, bool is_heap = false) {
|
||||
assert(top >= base, "must be");
|
||||
|
||||
LogStreamHandle(Trace, cds, map) lsh;
|
||||
if (lsh.is_enabled()) {
|
||||
os::print_hex_dump(&lsh, base, top, sizeof(address), 32, runtime_base);
|
||||
int unitsize = sizeof(address);
|
||||
if (is_heap && UseCompressedOops) {
|
||||
// This makes the compressed oop pointers easier to read, but
|
||||
// longs and doubles will be split into two words.
|
||||
unitsize = sizeof(narrowOop);
|
||||
}
|
||||
os::print_hex_dump(&lsh, base, top, unitsize, 32, runtime_base);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_header(FileMapInfo* mapinfo) {
|
||||
static void log_header(FileMapInfo* mapinfo) {
|
||||
LogStreamHandle(Info, cds, map) lsh;
|
||||
if (lsh.is_enabled()) {
|
||||
mapinfo->print(&lsh);
|
||||
@ -1052,41 +1092,38 @@ class ArchiveBuilder::CDSMapLogger : AllStatic {
|
||||
}
|
||||
|
||||
public:
|
||||
static void write(ArchiveBuilder* builder, FileMapInfo* mapinfo,
|
||||
GrowableArray<MemRegion> *closed_heap_regions,
|
||||
GrowableArray<MemRegion> *open_heap_regions,
|
||||
char* bitmap, size_t bitmap_size_in_bytes) {
|
||||
static void log(ArchiveBuilder* builder, FileMapInfo* mapinfo,
|
||||
GrowableArray<MemRegion> *closed_heap_regions,
|
||||
GrowableArray<MemRegion> *open_heap_regions,
|
||||
char* bitmap, size_t bitmap_size_in_bytes) {
|
||||
log_info(cds, map)("%s CDS archive map for %s", DumpSharedSpaces ? "Static" : "Dynamic", mapinfo->full_path());
|
||||
|
||||
address header = address(mapinfo->header());
|
||||
address header_end = header + mapinfo->header()->header_size();
|
||||
write_region("header", header, header_end, 0);
|
||||
write_header(mapinfo);
|
||||
write_data(header, header_end, 0);
|
||||
log_region("header", header, header_end, 0);
|
||||
log_header(mapinfo);
|
||||
log_data(header, header_end, 0);
|
||||
|
||||
DumpRegion* rw_region = &builder->_rw_region;
|
||||
DumpRegion* ro_region = &builder->_ro_region;
|
||||
|
||||
write_dump_region("rw region", rw_region);
|
||||
write_objects(rw_region, &builder->_rw_src_objs);
|
||||
|
||||
write_dump_region("ro region", ro_region);
|
||||
write_objects(ro_region, &builder->_ro_src_objs);
|
||||
log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs);
|
||||
log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs);
|
||||
|
||||
address bitmap_end = address(bitmap + bitmap_size_in_bytes);
|
||||
write_region("bitmap", address(bitmap), bitmap_end, 0);
|
||||
write_data(header, header_end, 0);
|
||||
log_region("bitmap", address(bitmap), bitmap_end, 0);
|
||||
log_data((address)bitmap, bitmap_end, 0);
|
||||
|
||||
if (closed_heap_regions != NULL) {
|
||||
write_heap_region("closed heap region", closed_heap_regions);
|
||||
log_heap_regions("closed heap region", closed_heap_regions);
|
||||
}
|
||||
if (open_heap_regions != NULL) {
|
||||
write_heap_region("open heap region", open_heap_regions);
|
||||
log_heap_regions("open heap region", open_heap_regions);
|
||||
}
|
||||
|
||||
log_info(cds, map)("[End of CDS archive map]");
|
||||
}
|
||||
};
|
||||
}; // end ArchiveBuilder::CDSMapLogger
|
||||
|
||||
void ArchiveBuilder::print_stats() {
|
||||
_alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used()));
|
||||
@ -1140,9 +1177,10 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
|
||||
}
|
||||
|
||||
if (log_is_enabled(Info, cds, map)) {
|
||||
CDSMapLogger::write(this, mapinfo, closed_heap_regions, open_heap_regions,
|
||||
bitmap, bitmap_size_in_bytes);
|
||||
CDSMapLogger::log(this, mapinfo, closed_heap_regions, open_heap_regions,
|
||||
bitmap, bitmap_size_in_bytes);
|
||||
}
|
||||
CDS_JAVA_HEAP_ONLY(HeapShared::destroy_archived_object_cache());
|
||||
FREE_C_HEAP_ARRAY(char, bitmap);
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,9 @@
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/compressedOops.inline.hpp"
|
||||
#include "oops/fieldStreams.inline.hpp"
|
||||
#include "oops/objArrayOop.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/fieldDescriptor.inline.hpp"
|
||||
#include "runtime/globals_extension.hpp"
|
||||
@ -213,6 +214,7 @@ void HeapShared::reset_archived_object_states(TRAPS) {
|
||||
}
|
||||
|
||||
HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = NULL;
|
||||
HeapShared::OriginalObjectTable* HeapShared::_original_object_table = NULL;
|
||||
oop HeapShared::find_archived_heap_object(oop obj) {
|
||||
assert(DumpSharedSpaces, "dump-time only");
|
||||
ArchivedObjectCache* cache = archived_object_cache();
|
||||
@ -317,6 +319,9 @@ oop HeapShared::archive_object(oop obj) {
|
||||
ArchivedObjectCache* cache = archived_object_cache();
|
||||
CachedOopInfo info = make_cached_oop_info(archived_oop);
|
||||
cache->put(obj, info);
|
||||
if (_original_object_table != NULL) {
|
||||
_original_object_table->put(archived_oop, obj);
|
||||
}
|
||||
if (log_is_enabled(Debug, cds, heap)) {
|
||||
ResourceMark rm;
|
||||
log_debug(cds, heap)("Archived heap object " PTR_FORMAT " ==> " PTR_FORMAT " : %s",
|
||||
@ -466,7 +471,7 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions,
|
||||
NoSafepointVerifier nsv;
|
||||
|
||||
// Cache for recording where the archived objects are copied to
|
||||
create_archived_object_cache();
|
||||
create_archived_object_cache(log_is_enabled(Info, cds, map));
|
||||
|
||||
log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]",
|
||||
UseCompressedOops ? p2i(CompressedOops::begin()) :
|
||||
@ -480,7 +485,6 @@ void HeapShared::archive_objects(GrowableArray<MemRegion>* closed_regions,
|
||||
copy_open_objects(open_regions);
|
||||
|
||||
CDSHeapVerifier::verify();
|
||||
destroy_archived_object_cache();
|
||||
}
|
||||
|
||||
G1HeapVerifier::verify_archive_regions();
|
||||
@ -532,6 +536,12 @@ void HeapShared::copy_open_objects(GrowableArray<MemRegion>* open_regions) {
|
||||
|
||||
// Copy _pending_archive_roots into an objArray
|
||||
void HeapShared::copy_roots() {
|
||||
// HeapShared::roots() points into an ObjArray in the open archive region. A portion of the
|
||||
// objects in this array are discovered during HeapShared::archive_objects(). For example,
|
||||
// in HeapShared::archive_reachable_objects_from() -> HeapShared::check_enum_obj().
|
||||
// However, HeapShared::archive_objects() happens inside a safepoint, so we can't
|
||||
// allocate a "regular" ObjArray and pass the result to HeapShared::archive_object().
|
||||
// Instead, we have to roll our own alloc/copy routine here.
|
||||
int length = _pending_roots != NULL ? _pending_roots->length() : 0;
|
||||
size_t size = objArrayOopDesc::object_size(length);
|
||||
Klass* k = Universe::objectArrayKlassObj(); // already relocated to point to archived klass
|
||||
|
@ -247,12 +247,19 @@ private:
|
||||
}
|
||||
|
||||
typedef ResourceHashtable<oop, CachedOopInfo,
|
||||
15889, // prime number
|
||||
36137, // prime number
|
||||
ResourceObj::C_HEAP,
|
||||
mtClassShared,
|
||||
HeapShared::oop_hash> ArchivedObjectCache;
|
||||
static ArchivedObjectCache* _archived_object_cache;
|
||||
|
||||
typedef ResourceHashtable<oop, oop,
|
||||
36137, // prime number
|
||||
ResourceObj::C_HEAP,
|
||||
mtClassShared,
|
||||
HeapShared::oop_hash> OriginalObjectTable;
|
||||
static OriginalObjectTable* _original_object_table;
|
||||
|
||||
class DumpTimeKlassSubGraphInfoTable
|
||||
: public ResourceHashtable<Klass*, KlassSubGraphInfo,
|
||||
137, // prime number
|
||||
@ -375,17 +382,36 @@ private:
|
||||
static void fill_failed_loaded_region();
|
||||
public:
|
||||
static void reset_archived_object_states(TRAPS);
|
||||
static void create_archived_object_cache() {
|
||||
static void create_archived_object_cache(bool create_orig_table) {
|
||||
_archived_object_cache =
|
||||
new (ResourceObj::C_HEAP, mtClass)ArchivedObjectCache();
|
||||
if (create_orig_table) {
|
||||
_original_object_table =
|
||||
new (ResourceObj::C_HEAP, mtClass)OriginalObjectTable();
|
||||
} else {
|
||||
_original_object_table = NULL;
|
||||
}
|
||||
}
|
||||
static void destroy_archived_object_cache() {
|
||||
delete _archived_object_cache;
|
||||
_archived_object_cache = NULL;
|
||||
if (_original_object_table != NULL) {
|
||||
delete _original_object_table;
|
||||
_original_object_table = NULL;
|
||||
}
|
||||
}
|
||||
static ArchivedObjectCache* archived_object_cache() {
|
||||
return _archived_object_cache;
|
||||
}
|
||||
static oop get_original_object(oop archived_object) {
|
||||
assert(_original_object_table != NULL, "sanity");
|
||||
oop* r = _original_object_table->get(archived_object);
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
return *r;
|
||||
}
|
||||
}
|
||||
|
||||
static oop find_archived_heap_object(oop obj);
|
||||
static oop archive_object(oop obj);
|
||||
|
Loading…
x
Reference in New Issue
Block a user