Skip to content

Commit 36e2097

Browse files
committed
8255917: runtime/cds/SharedBaseAddress.java failed "assert(reserved_rgn != 0LL) failed: No reserved region"
Reviewed-by: ccheung, iklam, stuefe
1 parent d53ee62 commit 36e2097

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
@@ -1369,10 +1369,13 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
13691369
assert(static_mapinfo->mapping_end_offset() == dynamic_mapinfo->mapping_base_offset(), "no gap");
13701370
}
13711371

1372-
ReservedSpace archive_space_rs, class_space_rs;
1372+
ReservedSpace total_space_rs, archive_space_rs, class_space_rs;
13731373
MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
1374-
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo, dynamic_mapinfo,
1375-
use_requested_addr, archive_space_rs,
1374+
char* mapped_base_address = reserve_address_space_for_archives(static_mapinfo,
1375+
dynamic_mapinfo,
1376+
use_requested_addr,
1377+
total_space_rs,
1378+
archive_space_rs,
13761379
class_space_rs);
13771380
if (mapped_base_address == NULL) {
13781381
result = MAP_ARCHIVE_MMAP_FAILURE;
@@ -1422,6 +1425,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14221425
// this with use_requested_addr, since we're going to patch all the
14231426
// pointers anyway so there's no benefit to mmap.
14241427
if (use_requested_addr) {
1428+
assert(!total_space_rs.is_reserved(), "Should not be reserved for Windows");
14251429
log_info(cds)("Windows mmap workaround: releasing archive space.");
14261430
archive_space_rs.release();
14271431
}
@@ -1477,6 +1481,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14771481
// cover both archive and class space.
14781482
address cds_base = (address)static_mapinfo->mapped_base();
14791483
address ccs_end = (address)class_space_rs.end();
1484+
assert(ccs_end > cds_base, "Sanity check");
14801485
CompressedKlassPointers::initialize(cds_base, ccs_end - cds_base);
14811486

14821487
// map_heap_regions() compares the current narrow oop and klass encodings
@@ -1489,7 +1494,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
14891494
} else {
14901495
unmap_archive(static_mapinfo);
14911496
unmap_archive(dynamic_mapinfo);
1492-
release_reserved_spaces(archive_space_rs, class_space_rs);
1497+
release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs);
14931498
}
14941499

14951500
return result;
@@ -1538,6 +1543,10 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
15381543
// Return:
15391544
//
15401545
// - On success:
1546+
// - total_space_rs will be reserved as whole for archive_space_rs and
1547+
// class_space_rs if UseCompressedClassPointers is true.
1548+
// On Windows, try reserve archive_space_rs and class_space_rs
1549+
// separately first if use_archive_base_addr is true.
15411550
// - archive_space_rs will be reserved and large enough to host static and
15421551
// if needed dynamic archive: [Base, A).
15431552
// archive_space_rs.base and size will be aligned to CDS reserve
@@ -1552,6 +1561,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
15521561
char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_mapinfo,
15531562
FileMapInfo* dynamic_mapinfo,
15541563
bool use_archive_base_addr,
1564+
ReservedSpace& total_space_rs,
15551565
ReservedSpace& archive_space_rs,
15561566
ReservedSpace& class_space_rs) {
15571567

@@ -1617,34 +1627,53 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
16171627
align_up(archive_space_size + gap_size + class_space_size,
16181628
os::vm_allocation_granularity());
16191629

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

1641-
// Now split up the space into ccs and cds archive. For simplicity, just leave
1642-
// the gap reserved at the end of the archive space.
1643-
archive_space_rs = total_rs.first_part(ccs_begin_offset,
1644-
(size_t)os::vm_allocation_granularity(),
1645-
/*split=*/true);
1646-
class_space_rs = total_rs.last_part(ccs_begin_offset);
1657+
if (!total_space_rs.is_reserved()) {
1658+
return NULL;
1659+
}
16471660

1661+
// Paranoid checks:
1662+
assert(base_address == NULL || (address)total_space_rs.base() == base_address,
1663+
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_space_rs.base()));
1664+
assert(is_aligned(total_space_rs.base(), archive_space_alignment), "Sanity");
1665+
assert(total_space_rs.size() == total_range_size, "Sanity");
1666+
assert(CompressedKlassPointers::is_valid_base((address)total_space_rs.base()), "Sanity");
1667+
1668+
// Now split up the space into ccs and cds archive. For simplicity, just leave
1669+
// the gap reserved at the end of the archive space. Do not do real splitting.
1670+
archive_space_rs = total_space_rs.first_part(ccs_begin_offset,
1671+
(size_t)os::vm_allocation_granularity(),
1672+
/*split=*/false);
1673+
class_space_rs = total_space_rs.last_part(ccs_begin_offset);
1674+
MemTracker::record_virtual_memory_split_reserved(total_space_rs.base(), total_space_rs.size(),
1675+
ccs_begin_offset);
1676+
}
16481677
assert(is_aligned(archive_space_rs.base(), archive_space_alignment), "Sanity");
16491678
assert(is_aligned(archive_space_rs.size(), archive_space_alignment), "Sanity");
16501679
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
16631692

16641693
}
16651694

1666-
void MetaspaceShared::release_reserved_spaces(ReservedSpace& archive_space_rs,
1695+
void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs,
1696+
ReservedSpace& archive_space_rs,
16671697
ReservedSpace& class_space_rs) {
1668-
if (archive_space_rs.is_reserved()) {
1669-
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
1670-
archive_space_rs.release();
1671-
}
1672-
if (class_space_rs.is_reserved()) {
1673-
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
1674-
class_space_rs.release();
1698+
if (total_space_rs.is_reserved()) {
1699+
log_debug(cds)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base()));
1700+
total_space_rs.release();
1701+
} else {
1702+
if (archive_space_rs.is_reserved()) {
1703+
log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base()));
1704+
archive_space_rs.release();
1705+
}
1706+
if (class_space_rs.is_reserved()) {
1707+
log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base()));
1708+
class_space_rs.release();
1709+
}
16751710
}
16761711
}
16771712

@@ -1715,6 +1750,7 @@ void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) {
17151750
assert(UseSharedSpaces, "must be runtime");
17161751
if (mapinfo != NULL) {
17171752
mapinfo->unmap_regions(archive_regions, archive_regions_count);
1753+
mapinfo->unmap_region(MetaspaceShared::bm);
17181754
mapinfo->set_is_mapped(false);
17191755
}
17201756
}

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 failed (" PTR_FORMAT ", " SIZE_FORMAT ")", 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 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_MSG = "os::release_memory failed";
43+
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.shouldNotContain(OS_RELEASE_MSG); // os::release only log release failed message
68+
}
69+
}

0 commit comments

Comments
 (0)