bool FileMapInfo::validate_header() { bool status = _header->validate(); if (status) { if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { if (!PrintSharedArchiveAndExit) { fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); status = false; } } } if (_paths_misc_info != NULL) { FREE_C_HEAP_ARRAY(char, _paths_misc_info); _paths_misc_info = NULL; } return status; }
// Map the whole region at once, assumed to be allocated contiguously. ReservedSpace FileMapInfo::reserve_shared_memory() { struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0]; char* requested_addr = si->_base; size_t size = FileMapInfo::shared_spaces_size(); // Reserve the space first, then map otherwise map will go right over some // other reserved memory (like the code cache). ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr); if (!rs.is_reserved()) { fail_continue("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr); return rs; } // the reserved virtual memory is for mapping class data sharing archive MemTracker::record_virtual_memory_type((address)rs.base(), mtClassShared); return rs; }
bool FileMapInfo::verify_region_checksum(int i) { if (!VerifySharedSpaces) { return true; } size_t sz = _header->_space[i]._used; if (sz == 0) { return true; // no data } if (MetaspaceShared::is_string_region(i) && StringTable::shared_string_ignored()) { return true; // shared string data are not mapped } const char* buf = _header->region_addr(i); int crc = ClassLoader::crc32(0, buf, (jint)sz); if (crc != _header->_space[i]._crc) { fail_continue("Checksum verification failed."); return false; } return true; }
char* FileMapInfo::map_region(int i) { struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i]; size_t used = si->_used; size_t alignment = os::vm_allocation_granularity(); size_t size = align_size_up(used, alignment); char *requested_addr = si->_base; // map the contents of the CDS archive in this memory char *base = os::map_memory(_fd, _full_path, si->_file_offset, requested_addr, size, si->_read_only, si->_allow_exec); if (base == NULL || base != si->_base) { fail_continue(err_msg("Unable to map %s shared space at required address.", shared_region_name[i])); return NULL; } #ifdef _WINDOWS // This call is Windows-only because the memory_type gets recorded for the other platforms // in method FileMapInfo::reserve_shared_memory(), which is not called on Windows. MemTracker::record_virtual_memory_type((address)base, mtClassShared); #endif return base; }
// Open the shared archive file, read and validate the header // information (version, boot classpath, etc.). If initialization // fails, shared spaces are disabled and the file is closed. [See // fail_continue.] // // Validation of the archive is done in two steps: // // [1] validate_header() - done here. This checks the header, including _paths_misc_info. // [2] validate_classpath_entry_table - this is done later, because the table is in the RW // region of the archive, which is not mapped yet. bool FileMapInfo::initialize() { assert(UseSharedSpaces, "UseSharedSpaces expected."); if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) { fail_continue("Tool agent requires sharing to be disabled."); return false; } if (!open_for_read()) { return false; } init_from_file(_fd); if (!validate_header()) { return false; } SharedReadOnlySize = _header->_space[0]._capacity; SharedReadWriteSize = _header->_space[1]._capacity; SharedMiscDataSize = _header->_space[2]._capacity; SharedMiscCodeSize = _header->_space[3]._capacity; return true; }
/** * 检查jar包是否可共享 */ bool FileMapInfo::validate() { if (_header._version != current_version()) { fail_continue("The shared archive file is the wrong version."); return false; } if (_header._magic != (int)0xf00baba2) { fail_continue("The shared archive file has a bad magic number."); return false; } if (strncmp(_header._jvm_ident, VM_Version::internal_vm_info_string(), JVM_IDENT_MAX-1) != 0) { fail_continue("The shared archive file was created by a different" " version or build of HotSpot."); return false; } // Cannot verify interpreter yet, as it can only be created after the GC // heap has been initialized. if (_header._num_jars >= JVM_SHARED_JARS_MAX) { fail_continue("Too many jar files to share."); return false; } // Build checks on classpath and jar files int num_jars_now = 0; ClassPathEntry *cpe = ClassLoader::classpath_entry(0); for ( ; cpe != NULL; cpe = cpe->next()) { if (cpe->is_jar_file()) { //jar包文件 if (num_jars_now < _header._num_jars) { // Jar file - verify timestamp and file size. struct stat st; const char *path = cpe->name(); if (os::stat(path, &st) != 0) { fail_continue("Unable to open jar file %s.", path); return false; } //jar包已被修改,不能共享 if (_header._jar[num_jars_now]._timestamp != st.st_mtime || _header._jar[num_jars_now]._filesize != st.st_size) { fail_continue("A jar file is not the one used while building" " the shared archive file."); return false; } } ++num_jars_now; } else { // If directories appear in boot classpath, they must be empty to // avoid having to verify each individual class file. const char* name = ((ClassPathDirEntry*)cpe)->name(); if (!os::dir_is_empty(name)) { //类路径 fail_continue("Boot classpath directory %s is not empty.", name); return false; } } } if (num_jars_now < _header._num_jars) { fail_continue("The number of jar files in the boot classpath is" " less than the number the shared archive was created with."); return false; } return true; }
bool FileMapInfo::map_string_regions() { #if INCLUDE_ALL_GCS if (UseG1GC && UseCompressedOops && UseCompressedClassPointers) { // Check that all the narrow oop and klass encodings match the archive if (narrow_oop_mode() != Universe::narrow_oop_mode() || narrow_oop_shift() != Universe::narrow_oop_shift() || narrow_klass_base() != Universe::narrow_klass_base() || narrow_klass_shift() != Universe::narrow_klass_shift()) { if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) { tty->print_cr("Shared string data from the CDS archive is being ignored. " "The current CompressedOops/CompressedClassPointers encoding differs from " "that archived due to heap size change. The archive was dumped using max heap " "size %dM.", max_heap_size()/M); } } else { string_ranges = new MemRegion[MetaspaceShared::max_strings]; struct FileMapInfo::FileMapHeader::space_info* si; for (int i = MetaspaceShared::first_string; i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) { si = &_header->_space[i]; size_t used = si->_used; if (used > 0) { size_t size = used; char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null( (narrowOop)si->_addr._offset)); string_ranges[num_ranges] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize); num_ranges ++; } } if (num_ranges == 0) { StringTable::ignore_shared_strings(true); return true; // no shared string data } // Check that ranges are within the java heap if (!G1CollectedHeap::heap()->check_archive_addresses(string_ranges, num_ranges)) { fail_continue("Unable to allocate shared string space: range is not " "within java heap."); return false; } // allocate from java heap if (!G1CollectedHeap::heap()->alloc_archive_regions(string_ranges, num_ranges)) { fail_continue("Unable to allocate shared string space: range is " "already in use."); return false; } // Map the string data. No need to call MemTracker::record_virtual_memory_type() // for mapped string regions as they are part of the reserved java heap, which // is already recorded. for (int i = 0; i < num_ranges; i++) { si = &_header->_space[MetaspaceShared::first_string + i]; char* addr = (char*)string_ranges[i].start(); char* base = os::map_memory(_fd, _full_path, si->_file_offset, addr, string_ranges[i].byte_size(), si->_read_only, si->_allow_exec); if (base == NULL || base != addr) { fail_continue("Unable to map shared string space at required address."); return false; } } if (!verify_string_regions()) { fail_continue("Shared string regions are corrupt"); return false; } // the shared string data is mapped successfully return true; } } else { if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) { tty->print_cr("Shared string data from the CDS archive is being ignored. UseG1GC, " "UseCompressedOops and UseCompressedClassPointers are required."); } } // if we get here, the shared string data is not mapped assert(string_ranges == NULL && num_ranges == 0, "sanity"); StringTable::ignore_shared_strings(true); #endif return true; }