Skip to content

Commit 905dd80

Browse files
Yumin QiYumin Qi
authored andcommitted
8255917: runtime/cds/SharedBaseAddress.java failed "assert(reserved_rgn != 0LL) failed: No reserved region"
1 parent f9c9bf0 commit 905dd80

File tree

8 files changed

+180
-47
lines changed

8 files changed

+180
-47
lines changed

src/hotspot/share/memory/filemap.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,10 @@ char* FileMapInfo::map_bitmap_region() {
16801680

16811681
si->set_mapped_base(bitmap_base);
16821682
si->set_mapped_from_file(true);
1683+
log_info(cds)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)",
1684+
is_static() ? "static " : "dynamic",
1685+
MetaspaceShared::bm, p2i(si->mapped_base()), p2i(si->mapped_end()),
1686+
shared_region_name[MetaspaceShared::bm]);
16831687
return bitmap_base;
16841688
}
16851689

src/hotspot/share/memory/metaspaceShared.cpp

Lines changed: 73 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,10 +1364,13 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
13641364
assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap");
13651365
}
13661366

1367-
ReservedSpace archive_space_rs, class_space_rs;
1367+
ReservedSpace total_space_rs, archive_space_rs, class_space_rs;
13681368
MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
1369-
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo,
1370-
use_requested_addr, archive_space_rs,
1369+
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo,
1370+
dynamic_mapinfo,
1371+
use_requested_addr,
1372+
total_space_rs,
1373+
archive_space_rs,
13711374
class_space_rs);
13721375
if (mapped_base_address == NULL) {
13731376
result = MAP_ARCHIVE_MMAP_FAILURE;
@@ -1417,6 +1420,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14171420
// this with use_requested_addr, since we're going to patch all the
14181421
// pointers anyway so there's no benefit to mmap.
14191422
if (use_requested_addr) {
1423+
assert(!total_space_rs.is_reserved(), "Should not be reserved for Windows");
14201424
log_info(cds)("Windows mmap workaround: releasing archive space.");
14211425
archive_space_rs.release();
14221426
}
@@ -1472,6 +1476,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14721476
// cover both archive and class space.
14731477
address cds_base = (address)static_mapinfo->mapped_base();
14741478
address ccs_end = (address)class_space_rs.end();
1479+
assert(ccs_end > cds_base, "Sanity check");
14751480
CompressedKlassPointers::initialize(cds_base, ccs_end - cds_base);
14761481

14771482
// map_heap_regions() compares the current narrow oop and klass encodings
@@ -1484,7 +1489,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14841489
} else {
14851490
unmap_archive(static_mapinfo);
14861491
unmap_archive(dynamic_mapinfo);
1487-
release_reserved_spaces(archive_space_rs, class_space_rs);
1492+
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
14881493
}
14891494

14901495
return result;
@@ -1533,6 +1538,10 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
15331538
// Return:
15341539
//
15351540
// - On success:
1541+
// - total_space_rs will be reserved as whole for archive_space_rs and
1542+
// class_space_rs if UseCompressedClassPointers is true.
1543+
// On Windows, try reserve archive_space_rs and class_space_rs
1544+
// separately first if use_archive_base_addr is true.
15361545
// - archive_space_rs will be reserved and large enough to host static and
15371546
// if needed dynamic archive: [Base, A).
15381547
// archive_space_rs.base and size will be aligned to CDS reserve
@@ -1547,6 +1556,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
15471556
char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
15481557
FileMapInfo* dynamic_mapinfo,
15491558
bool use_archive_base_addr,
1559+
ReservedSpace& total_space_rs,
15501560
ReservedSpace& archive_space_rs,
15511561
ReservedSpace& class_space_rs) {
15521562

@@ -1612,34 +1622,53 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
16121622
align_up(archive_space_size + gap_size + class_space_size,
16131623
os::vm_allocation_granularity());
16141624

1615-
ReservedSpace total_rs;
1616-
if (base_address != NULL) {
1617-
// Reserve at the given archive base address, or not at all.
1618-
total_rs = ReservedSpace(total_range_size, archive_space_alignment,
1619-
false /* bool large */, (char*) base_address);
1625+
assert(total_range_size > ccs_begin_offset, "must be");
1626+
if (use_windows_memory_mapping() && use_archive_base_addr) {
1627+
if (base_address != nullptr) {
1628+
// On Windows, we cannot safely split a reserved memory space into two (see JDK-8255917).
1629+
// Hence, we optimistically reserve archive space and class space side-by-side. We only
1630+
// do this for use_archive_base_addr=true since for use_archive_base_addr=false case
1631+
// caller will not split the combined space for mapping, instead read the archive data
1632+
// via sequential file IO.
1633+
address ccs_base = base_address + archive_space_size + gap_size;
1634+
archive_space_rs = ReservedSpace(archive_space_size, archive_space_alignment,
1635+
false /* large */, (char*)base_address);
1636+
class_space_rs = ReservedSpace(class_space_size, class_space_alignment,
1637+
false /* large */, (char*)ccs_base);
1638+
}
1639+
if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) {
1640+
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
1641+
return NULL;
1642+
}
16201643
} else {
1621-
// Reserve at any address, but leave it up to the platform to choose a good one.
1622-
total_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size);
1623-
}
1624-
1625-
if (!total_rs.is_reserved()) {
1626-
return NULL;
1627-
}
1628-
1629-
// Paranoid checks:
1630-
assert(base_address == NULL || (address)total_rs.base() == base_address,
1631-
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_rs.base()));
1632-
assert(is_aligned(total_rs.base(), archive_space_alignment), "Sanity");
1633-
assert(total_rs.size() == total_range_size, "Sanity");
1634-
assert(CompressedKlassPointers::is_valid_base((address)total_rs.base()), "Sanity");
1644+
if (use_archive_base_addr && base_address != nullptr) {
1645+
total_space_rs = ReservedSpace(total_range_size, archive_space_alignment,
1646+
false /* bool large */, (char*) base_address);
1647+
} else {
1648+
// Reserve at any address, but leave it up to the platform to choose a good one.
1649+
total_space_rs = Metaspace::reserve_address_space_for_compressed_classes(total_range_size);
1650+
}
16351651

1636-
// Now split up the space into ccs and cds archive. For simplicity, just leave
1637-
// the gap reserved at the end of the archive space.
1638-
archive_space_rs = total_rs.first_part(ccs_begin_offset,
1639-
(size_t)os::vm_allocation_granularity(),
1640-
/*split=*/true);
1641-
class_space_rs = total_rs.last_part(ccs_begin_offset);
1652+
if (!total_space_rs.is_reserved()) {
1653+
return NULL;
1654+
}
16421655

1656+
// Paranoid checks:
1657+
assert(base_address == NULL || (address)total_space_rs.base() == base_address,
1658+
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_space_rs.base()));
1659+
assert(is_aligned(total_space_rs.base(), archive_space_alignment), "Sanity");
1660+
assert(total_space_rs.size() == total_range_size, "Sanity");
1661+
assert(CompressedKlassPointers::is_valid_base((address)total_space_rs.base()), "Sanity");
1662+
1663+
// Now split up the space into ccs and cds archive. For simplicity, just leave
1664+
// the gap reserved at the end of the archive space. Do not do real splitting.
1665+
archive_space_rs = total_space_rs.first_part(ccs_begin_offset,
1666+
(size_t)os::vm_allocation_granularity(),
1667+
/*split=*/false);
1668+
class_space_rs = total_space_rs.last_part(ccs_begin_offset);
1669+
MemTracker::record_virtual_memory_split_reserved(total_space_rs.base(), total_space_rs.size(),
1670+
ccs_begin_offset);
1671+
}
16431672
assert(is_aligned(archive_space_rs.base(), archive_space_alignment), "Sanity");
16441673
assert(is_aligned(archive_space_rs.size(), archive_space_alignment), "Sanity");
16451674
assert(is_aligned(class_space_rs.base(), class_space_alignment), "Sanity");
@@ -1658,15 +1687,21 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
16581687

16591688
}
16601689

1661-
void MetaspaceShared::release_reserved_spaces(ReservedSpace& archive_space_rs,
1690+
void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs,
1691+
ReservedSpace& archive_space_rs,
16621692
ReservedSpace& class_space_rs) {
1663-
if (archive_space_rs.is_reserved()) {
1664-
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
1665-
archive_space_rs.release();
1666-
}
1667-
if (class_space_rs.is_reserved()) {
1668-
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
1669-
class_space_rs.release();
1693+
if (total_space_rs.is_reserved()) {
1694+
log_debug(cds)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base()));
1695+
total_space_rs.release();
1696+
} else {
1697+
if (archive_space_rs.is_reserved()) {
1698+
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
1699+
archive_space_rs.release();
1700+
}
1701+
if (class_space_rs.is_reserved()) {
1702+
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
1703+
class_space_rs.release();
1704+
}
16701705
}
16711706
}
16721707

@@ -1710,6 +1745,7 @@ void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) {
17101745
assert(UseSharedSpaces, "must be runtime");
17111746
if (mapinfo != NULL) {
17121747
mapinfo->unmap_regions(archive_regions, archive_regions_count);
1748+
mapinfo->unmap_region(MetaspaceShared::bm);
17131749
mapinfo->set_is_mapped(false);
17141750
}
17151751
}

src/hotspot/share/memory/metaspaceShared.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,12 @@ class MetaspaceShared : AllStatic {
288288
static char* reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
289289
FileMapInfo* dynamic_mapinfo,
290290
bool use_archive_base_addr,
291+
ReservedSpace& total_space_rs,
291292
ReservedSpace& archive_space_rs,
292293
ReservedSpace& class_space_rs);
293-
static void release_reserved_spaces(ReservedSpace& archive_space_rs,
294-
ReservedSpace& class_space_rs);
294+
static void release_reserved_spaces(ReservedSpace& total_space_rs,
295+
ReservedSpace& archive_space_rs,
296+
ReservedSpace& class_space_rs);
295297
static MapArchiveResult map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs);
296298
static void unmap_archive(FileMapInfo* mapinfo);
297299
};

src/hotspot/share/runtime/os.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,9 @@ bool os::release_memory(char* addr, size_t bytes) {
17231723
} else {
17241724
res = pd_release_memory(addr, bytes);
17251725
}
1726+
if (!res) {
1727+
log_info(os)("os::release_memory(" PTR_FORMAT ", " SIZE_FORMAT ") failed", p2i(addr), bytes);
1728+
}
17261729
return res;
17271730
}
17281731

src/hotspot/share/services/virtualMemoryTracker.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ bool VirtualMemoryTracker::add_committed_region(address addr, size_t size,
444444
assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
445445
bool result = reserved_rgn->add_committed_region(addr, size, stack);
446446
log_debug(nmt)("Add committed region \'%s\'(" INTPTR_FORMAT ", " SIZE_FORMAT ") %s",
447-
rgn.flag_name(), p2i(rgn.base()), rgn.size(), (result ? "Succeeded" : "Failed"));
447+
reserved_rgn->flag_name(), p2i(rgn.base()), rgn.size(), (result ? "Succeeded" : "Failed"));
448448
return result;
449449
}
450450

@@ -506,12 +506,26 @@ bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) {
506506
return false;
507507
}
508508

509-
if (reserved_rgn->flag() == mtClassShared &&
510-
reserved_rgn->contain_region(addr, size)) {
511-
// This is an unmapped CDS region, which is part of the reserved shared
512-
// memory region.
513-
// See special handling in VirtualMemoryTracker::add_reserved_region also.
514-
return true;
509+
if (reserved_rgn->flag() == mtClassShared) {
510+
if (reserved_rgn->contain_region(addr, size)) {
511+
// This is an unmapped CDS region, which is part of the reserved shared
512+
// memory region.
513+
// See special handling in VirtualMemoryTracker::add_reserved_region also.
514+
return true;
515+
}
516+
517+
if (size > reserved_rgn->size()) {
518+
// This is from release the whole region spanning from archive space to class space,
519+
// so we release them altogether.
520+
ReservedMemoryRegion class_rgn(addr + reserved_rgn->size(),
521+
(size - reserved_rgn->size()));
522+
ReservedMemoryRegion* cls_rgn = _reserved_regions->find(class_rgn);
523+
assert(cls_rgn != NULL, "Class space region not recorded?");
524+
assert(cls_rgn->flag() == mtClass, "Must be class type");
525+
remove_released_region(reserved_rgn);
526+
remove_released_region(cls_rgn);
527+
return true;
528+
}
515529
}
516530

517531
VirtualMemorySummary::record_released_memory(size, reserved_rgn->flag());

test/hotspot/jtreg/TEST.groups

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ hotspot_appcds_dynamic = \
338338
-runtime/cds/appcds/LambdaProxyClasslist.java \
339339
-runtime/cds/appcds/LongClassListPath.java \
340340
-runtime/cds/appcds/LotsOfClasses.java \
341+
-runtime/cds/appcds/MismatchedPathTriggerMemoryRelease.java \
341342
-runtime/cds/appcds/NonExistClasspath.java \
342343
-runtime/cds/appcds/RelativePath.java \
343344
-runtime/cds/appcds/SharedArchiveConsistency.java \

test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public class SharedBaseAddress {
5050
"0", // always let OS pick the base address at runtime (ASLR for CDS archive)
5151
};
5252

53+
// failed pattern
54+
private static String failedPattern = "os::release_memory\\(0x[0-9a-fA-F]*,\\s[0-9]*\\)\\sfailed";
55+
5356
public static void main(String[] args) throws Exception {
5457

5558
for (String testEntry : testTable) {
@@ -68,7 +71,8 @@ public static void main(String[] args) throws Exception {
6871
OutputAnalyzer out = CDSTestUtils.runWithArchiveAndCheck(opts);
6972
if (testEntry.equals("0")) {
7073
out.shouldContain("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address.")
71-
.shouldContain("Try to map archive(s) at an alternative address");
74+
.shouldContain("Try to map archive(s) at an alternative address")
75+
.shouldNotMatch(failedPattern);
7276
}
7377
}
7478
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
/*
26+
* @test MismatchedPathTriggerMemoryRelease
27+
* @summary Mismatched path at runtime will cause reserved memory released
28+
* @requires vm.cds
29+
* @library /test/lib
30+
* @compile test-classes/Hello.java
31+
* @run main/timeout=240 MismatchedPathTriggerMemoryRelease
32+
*/
33+
34+
import jdk.test.lib.process.OutputAnalyzer;
35+
36+
public class MismatchedPathTriggerMemoryRelease {
37+
private static String ERR_MSGS[] = {
38+
"UseSharedSpaces: shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)",
39+
"UseSharedSpaces: Unable to map shared spaces"};
40+
private static String RELEASE_SPACE_MATCH =
41+
"Released shared space\\s(\\(archive\\s*\\+\\s*class\\) | ?)0(x|X)[0-9a-fA-F]+$";
42+
private static String OS_RELEASE_MATCH =
43+
"os::release_memory\\(0(x|X)[0-9a-fA-F]+,\\s[0-9]+\\)\\sfailed";
44+
public static void main(String[] args) throws Exception {
45+
String appJar = JarBuilder.getOrCreateHelloJar();
46+
47+
OutputAnalyzer dumpOutput = TestCommon.dump(
48+
appJar, new String[] {"Hello"}, "-XX:SharedBaseAddress=0");
49+
TestCommon.checkDump(dumpOutput, "Loading classes to share");
50+
51+
// Normal exit
52+
OutputAnalyzer execOutput = TestCommon.exec(appJar, "Hello");
53+
TestCommon.checkExec(execOutput, "Hello World");
54+
55+
// mismatched jar
56+
execOutput = TestCommon.exec("non-exist.jar",
57+
"-Xshare:auto",
58+
"-Xlog:os,cds=debug",
59+
"-XX:NativeMemoryTracking=detail",
60+
"-XX:SharedBaseAddress=0",
61+
"Hello");
62+
execOutput.shouldHaveExitValue(1);
63+
for (String err : ERR_MSGS) {
64+
execOutput.shouldContain(err);
65+
}
66+
execOutput.shouldMatch(RELEASE_SPACE_MATCH);
67+
execOutput.shouldNotMatch(OS_RELEASE_MATCH); // os::release only log release failed message
68+
}
69+
}

0 commit comments

Comments
 (0)