8255917: runtime/cds/SharedBaseAddress.java failed "assert(reserved_rgn != 0LL) failed: No reserved region"
Reviewed-by: ccheung, iklam, stuefe
This commit is contained in:
parent
d53ee6219b
commit
36e2097401
@ -1680,6 +1680,10 @@ char* FileMapInfo::map_bitmap_region() {
|
||||
|
||||
si->set_mapped_base(bitmap_base);
|
||||
si->set_mapped_from_file(true);
|
||||
log_info(cds)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)",
|
||||
is_static() ? "static " : "dynamic",
|
||||
MetaspaceShared::bm, p2i(si->mapped_base()), p2i(si->mapped_end()),
|
||||
shared_region_name[MetaspaceShared::bm]);
|
||||
return bitmap_base;
|
||||
}
|
||||
|
||||
|
@ -1369,10 +1369,13 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap");
|
||||
}
|
||||
|
||||
ReservedSpace archive_space_rs, class_space_rs;
|
||||
ReservedSpace total_space_rs, archive_space_rs, class_space_rs;
|
||||
MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
|
||||
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo,
|
||||
use_requested_addr, archive_space_rs,
|
||||
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo,
|
||||
dynamic_mapinfo,
|
||||
use_requested_addr,
|
||||
total_space_rs,
|
||||
archive_space_rs,
|
||||
class_space_rs);
|
||||
if (mapped_base_address == NULL) {
|
||||
result = MAP_ARCHIVE_MMAP_FAILURE;
|
||||
@ -1422,6 +1425,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
// this with use_requested_addr, since we're going to patch all the
|
||||
// pointers anyway so there's no benefit to mmap.
|
||||
if (use_requested_addr) {
|
||||
assert(!total_space_rs.is_reserved(), "Should not be reserved for Windows");
|
||||
log_info(cds)("Windows mmap workaround: releasing archive space.");
|
||||
archive_space_rs.release();
|
||||
}
|
||||
@ -1477,6 +1481,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
// cover both archive and class space.
|
||||
address cds_base = (address)static_mapinfo->mapped_base();
|
||||
address ccs_end = (address)class_space_rs.end();
|
||||
assert(ccs_end > cds_base, "Sanity check");
|
||||
CompressedKlassPointers::initialize(cds_base, ccs_end - cds_base);
|
||||
|
||||
// map_heap_regions() compares the current narrow oop and klass encodings
|
||||
@ -1489,7 +1494,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
} else {
|
||||
unmap_archive(static_mapinfo);
|
||||
unmap_archive(dynamic_mapinfo);
|
||||
release_reserved_spaces(archive_space_rs, class_space_rs);
|
||||
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1538,6 +1543,10 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
// Return:
|
||||
//
|
||||
// - On success:
|
||||
// - total_space_rs will be reserved as whole for archive_space_rs and
|
||||
// class_space_rs if UseCompressedClassPointers is true.
|
||||
// On Windows, try reserve archive_space_rs and class_space_rs
|
||||
// separately first if use_archive_base_addr is true.
|
||||
// - archive_space_rs will be reserved and large enough to host static and
|
||||
// if needed dynamic archive: [Base, A).
|
||||
// archive_space_rs.base and size will be aligned to CDS reserve
|
||||
@ -1552,6 +1561,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
|
||||
char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
|
||||
FileMapInfo* dynamic_mapinfo,
|
||||
bool use_archive_base_addr,
|
||||
ReservedSpace& total_space_rs,
|
||||
ReservedSpace& archive_space_rs,
|
||||
ReservedSpace& class_space_rs) {
|
||||
|
||||
@ -1617,34 +1627,53 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
|
||||
align_up(archive_space_size + gap_size + class_space_size,
|
||||
os::vm_allocation_granularity());
|
||||
|
||||
ReservedSpace total_rs;
|
||||
if (base_address != NULL) {
|
||||
// Reserve at the given archive base address, or not at all.
|
||||
total_rs = ReservedSpace(total_range_size, archive_space_alignment,
|
||||
false /* bool large */, (char*) base_address);
|
||||
assert(total_range_size > ccs_begin_offset, "must be");
|
||||
if (use_windows_memory_mapping() && use_archive_base_addr) {
|
||||
if (base_address != nullptr) {
|
||||
// On Windows, we cannot safely split a reserved memory space into two (see JDK-8255917).
|
||||
// Hence, we optimistically reserve archive space and class space side-by-side. We only
|
||||
// do this for use_archive_base_addr=true since for use_archive_base_addr=false case
|
||||
// caller will not split the combined space for mapping, instead read the archive data
|
||||
// via sequential file IO.
|
||||
address ccs_base = base_address + archive_space_size + gap_size;
|
||||
archive_space_rs = ReservedSpace(archive_space_size, archive_space_alignment,
|
||||
false /* large */, (char*)base_address);
|
||||
class_space_rs = ReservedSpace(class_space_size, class_space_alignment,
|
||||
false /* large */, (char*)ccs_base);
|
||||
}
|
||||
if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) {
|
||||
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
// Reserve at any address, but leave it up to the platform to choose a good one.
|
||||
total_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size);
|
||||
if (use_archive_base_addr && base_address != nullptr) {
|
||||
total_space_rs = ReservedSpace(total_range_size, archive_space_alignment,
|
||||
false /* bool large */, (char*) base_address);
|
||||
} else {
|
||||
// Reserve at any address, but leave it up to the platform to choose a good one.
|
||||
total_space_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size);
|
||||
}
|
||||
|
||||
if (!total_space_rs.is_reserved()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Paranoid checks:
|
||||
assert(base_address == NULL || (address)total_space_rs.base() == base_address,
|
||||
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_space_rs.base()));
|
||||
assert(is_aligned(total_space_rs.base(), archive_space_alignment), "Sanity");
|
||||
assert(total_space_rs.size() == total_range_size, "Sanity");
|
||||
assert(CompressedKlassPointers::is_valid_base((address)total_space_rs.base()), "Sanity");
|
||||
|
||||
// Now split up the space into ccs and cds archive. For simplicity, just leave
|
||||
// the gap reserved at the end of the archive space. Do not do real splitting.
|
||||
archive_space_rs = total_space_rs.first_part(ccs_begin_offset,
|
||||
(size_t)os::vm_allocation_granularity(),
|
||||
/*split=*/false);
|
||||
class_space_rs = total_space_rs.last_part(ccs_begin_offset);
|
||||
MemTracker::record_virtual_memory_split_reserved(total_space_rs.base(), total_space_rs.size(),
|
||||
ccs_begin_offset);
|
||||
}
|
||||
|
||||
if (!total_rs.is_reserved()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Paranoid checks:
|
||||
assert(base_address == NULL || (address)total_rs.base() == base_address,
|
||||
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_rs.base()));
|
||||
assert(is_aligned(total_rs.base(), archive_space_alignment), "Sanity");
|
||||
assert(total_rs.size() == total_range_size, "Sanity");
|
||||
assert(CompressedKlassPointers::is_valid_base((address)total_rs.base()), "Sanity");
|
||||
|
||||
// Now split up the space into ccs and cds archive. For simplicity, just leave
|
||||
// the gap reserved at the end of the archive space.
|
||||
archive_space_rs = total_rs.first_part(ccs_begin_offset,
|
||||
(size_t)os::vm_allocation_granularity(),
|
||||
/*split=*/true);
|
||||
class_space_rs = total_rs.last_part(ccs_begin_offset);
|
||||
|
||||
assert(is_aligned(archive_space_rs.base(), archive_space_alignment), "Sanity");
|
||||
assert(is_aligned(archive_space_rs.size(), archive_space_alignment), "Sanity");
|
||||
assert(is_aligned(class_space_rs.base(), class_space_alignment), "Sanity");
|
||||
@ -1663,15 +1692,21 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
|
||||
|
||||
}
|
||||
|
||||
void MetaspaceShared::release_reserved_spaces(ReservedSpace& archive_space_rs,
|
||||
void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs,
|
||||
ReservedSpace& archive_space_rs,
|
||||
ReservedSpace& class_space_rs) {
|
||||
if (archive_space_rs.is_reserved()) {
|
||||
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
|
||||
archive_space_rs.release();
|
||||
}
|
||||
if (class_space_rs.is_reserved()) {
|
||||
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
|
||||
class_space_rs.release();
|
||||
if (total_space_rs.is_reserved()) {
|
||||
log_debug(cds)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base()));
|
||||
total_space_rs.release();
|
||||
} else {
|
||||
if (archive_space_rs.is_reserved()) {
|
||||
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
|
||||
archive_space_rs.release();
|
||||
}
|
||||
if (class_space_rs.is_reserved()) {
|
||||
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
|
||||
class_space_rs.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1715,6 +1750,7 @@ void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) {
|
||||
assert(UseSharedSpaces, "must be runtime");
|
||||
if (mapinfo != NULL) {
|
||||
mapinfo->unmap_regions(archive_regions, archive_regions_count);
|
||||
mapinfo->unmap_region(MetaspaceShared::bm);
|
||||
mapinfo->set_is_mapped(false);
|
||||
}
|
||||
}
|
||||
|
@ -288,10 +288,12 @@ private:
|
||||
static char* reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
|
||||
FileMapInfo* dynamic_mapinfo,
|
||||
bool use_archive_base_addr,
|
||||
ReservedSpace& total_space_rs,
|
||||
ReservedSpace& archive_space_rs,
|
||||
ReservedSpace& class_space_rs);
|
||||
static void release_reserved_spaces(ReservedSpace& archive_space_rs,
|
||||
ReservedSpace& class_space_rs);
|
||||
static void release_reserved_spaces(ReservedSpace& total_space_rs,
|
||||
ReservedSpace& archive_space_rs,
|
||||
ReservedSpace& class_space_rs);
|
||||
static MapArchiveResult map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs);
|
||||
static void unmap_archive(FileMapInfo* mapinfo);
|
||||
};
|
||||
|
@ -1723,6 +1723,9 @@ bool os::release_memory(char* addr, size_t bytes) {
|
||||
} else {
|
||||
res = pd_release_memory(addr, bytes);
|
||||
}
|
||||
if (!res) {
|
||||
log_info(os)("os::release_memory failed (" PTR_FORMAT ", " SIZE_FORMAT ")", p2i(addr), bytes);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ bool VirtualMemoryTracker::add_committed_region(address addr, size_t size,
|
||||
assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
|
||||
bool result = reserved_rgn->add_committed_region(addr, size, stack);
|
||||
log_debug(nmt)("Add committed region \'%s\'(" INTPTR_FORMAT ", " SIZE_FORMAT ") %s",
|
||||
rgn.flag_name(), p2i(rgn.base()), rgn.size(), (result ? "Succeeded" : "Failed"));
|
||||
reserved_rgn->flag_name(), p2i(rgn.base()), rgn.size(), (result ? "Succeeded" : "Failed"));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -506,12 +506,26 @@ bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reserved_rgn->flag() == mtClassShared &&
|
||||
reserved_rgn->contain_region(addr, size)) {
|
||||
// This is an unmapped CDS region, which is part of the reserved shared
|
||||
// memory region.
|
||||
// See special handling in VirtualMemoryTracker::add_reserved_region also.
|
||||
return true;
|
||||
if (reserved_rgn->flag() == mtClassShared) {
|
||||
if (reserved_rgn->contain_region(addr, size)) {
|
||||
// This is an unmapped CDS region, which is part of the reserved shared
|
||||
// memory region.
|
||||
// See special handling in VirtualMemoryTracker::add_reserved_region also.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size > reserved_rgn->size()) {
|
||||
// This is from release the whole region spanning from archive space to class space,
|
||||
// so we release them altogether.
|
||||
ReservedMemoryRegion class_rgn(addr + reserved_rgn->size(),
|
||||
(size - reserved_rgn->size()));
|
||||
ReservedMemoryRegion* cls_rgn = _reserved_regions->find(class_rgn);
|
||||
assert(cls_rgn != NULL, "Class space region not recorded?");
|
||||
assert(cls_rgn->flag() == mtClass, "Must be class type");
|
||||
remove_released_region(reserved_rgn);
|
||||
remove_released_region(cls_rgn);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualMemorySummary::record_released_memory(size, reserved_rgn->flag());
|
||||
|
@ -338,6 +338,7 @@ hotspot_appcds_dynamic = \
|
||||
-runtime/cds/appcds/LambdaProxyClasslist.java \
|
||||
-runtime/cds/appcds/LongClassListPath.java \
|
||||
-runtime/cds/appcds/LotsOfClasses.java \
|
||||
-runtime/cds/appcds/MismatchedPathTriggerMemoryRelease.java \
|
||||
-runtime/cds/appcds/NonExistClasspath.java \
|
||||
-runtime/cds/appcds/RelativePath.java \
|
||||
-runtime/cds/appcds/SharedArchiveConsistency.java \
|
||||
|
@ -50,6 +50,9 @@ public class SharedBaseAddress {
|
||||
"0", // always let OS pick the base address at runtime (ASLR for CDS archive)
|
||||
};
|
||||
|
||||
// failed pattern
|
||||
private static String failedPattern = "os::release_memory\\(0x[0-9a-fA-F]*,\\s[0-9]*\\)\\sfailed";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
for (String testEntry : testTable) {
|
||||
@ -68,7 +71,8 @@ public class SharedBaseAddress {
|
||||
OutputAnalyzer out = CDSTestUtils.runWithArchiveAndCheck(opts);
|
||||
if (testEntry.equals("0")) {
|
||||
out.shouldContain("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address.")
|
||||
.shouldContain("Try to map archive(s) at an alternative address");
|
||||
.shouldContain("Try to map archive(s) at an alternative address")
|
||||
.shouldNotMatch(failedPattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test MismatchedPathTriggerMemoryRelease
|
||||
* @summary Mismatched path at runtime will cause reserved memory released
|
||||
* @requires vm.cds
|
||||
* @library /test/lib
|
||||
* @compile test-classes/Hello.java
|
||||
* @run main MismatchedPathTriggerMemoryRelease
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class MismatchedPathTriggerMemoryRelease {
|
||||
private static String ERR_MSGS[] = {
|
||||
"UseSharedSpaces: shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)",
|
||||
"UseSharedSpaces: Unable to map shared spaces"};
|
||||
private static String RELEASE_SPACE_MATCH =
|
||||
"Released shared space\\s(\\(archive\\s*\\+\\s*class\\) | ?)0(x|X)[0-9a-fA-F]+$";
|
||||
private static String OS_RELEASE_MSG = "os::release_memory failed";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String appJar = JarBuilder.getOrCreateHelloJar();
|
||||
|
||||
OutputAnalyzer dumpOutput = TestCommon.dump(
|
||||
appJar, new String[] {"Hello"}, "-XX:SharedBaseAddress=0");
|
||||
TestCommon.checkDump(dumpOutput, "Loading classes to share");
|
||||
|
||||
// Normal exit
|
||||
OutputAnalyzer execOutput = TestCommon.exec(appJar, "Hello");
|
||||
TestCommon.checkExec(execOutput, "Hello World");
|
||||
|
||||
// mismatched jar
|
||||
execOutput = TestCommon.exec("non-exist.jar",
|
||||
"-Xshare:auto",
|
||||
"-Xlog:os,cds=debug",
|
||||
"-XX:NativeMemoryTracking=detail",
|
||||
"-XX:SharedBaseAddress=0",
|
||||
"Hello");
|
||||
execOutput.shouldHaveExitValue(1);
|
||||
for (String err : ERR_MSGS) {
|
||||
execOutput.shouldContain(err);
|
||||
}
|
||||
execOutput.shouldMatch(RELEASE_SPACE_MATCH);
|
||||
execOutput.shouldNotContain(OS_RELEASE_MSG); // os::release only log release failed message
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user