Merge
This commit is contained in:
commit
69d4ee5887
@ -23,7 +23,10 @@
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#include "runtime/atomic.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/virtualMemoryTracker.hpp"
|
||||
|
||||
size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)];
|
||||
@ -52,46 +55,41 @@ bool ReservedMemoryRegion::add_committed_region(address addr, size_t size, const
|
||||
if (all_committed()) return true;
|
||||
|
||||
CommittedMemoryRegion committed_rgn(addr, size, stack);
|
||||
LinkedListNode<CommittedMemoryRegion>* node = _committed_regions.find_node(committed_rgn);
|
||||
if (node != NULL) {
|
||||
LinkedListNode<CommittedMemoryRegion>* node = _committed_regions.head();
|
||||
|
||||
while (node != NULL) {
|
||||
CommittedMemoryRegion* rgn = node->data();
|
||||
if (rgn->same_region(addr, size)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rgn->adjacent_to(addr, size)) {
|
||||
// check if the next region covers this committed region,
|
||||
// the regions may not be merged due to different call stacks
|
||||
LinkedListNode<CommittedMemoryRegion>* next =
|
||||
node->next();
|
||||
if (next != NULL && next->data()->contain_region(addr, size)) {
|
||||
if (next->data()->same_region(addr, size)) {
|
||||
next->data()->set_call_stack(stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (rgn->call_stack()->equals(stack)) {
|
||||
// special case to expand prior region if there is no next region
|
||||
LinkedListNode<CommittedMemoryRegion>* next = node->next();
|
||||
if (next == NULL && rgn->call_stack()->equals(stack)) {
|
||||
VirtualMemorySummary::record_uncommitted_memory(rgn->size(), flag());
|
||||
// the two adjacent regions have the same call stack, merge them
|
||||
rgn->expand_region(addr, size);
|
||||
VirtualMemorySummary::record_committed_memory(rgn->size(), flag());
|
||||
return true;
|
||||
}
|
||||
VirtualMemorySummary::record_committed_memory(size, flag());
|
||||
if (rgn->base() > addr) {
|
||||
return _committed_regions.insert_before(committed_rgn, node) != NULL;
|
||||
} else {
|
||||
return _committed_regions.insert_after(committed_rgn, node) != NULL;
|
||||
}
|
||||
|
||||
if (rgn->overlap_region(addr, size)) {
|
||||
// Clear a space for this region in the case it overlaps with any regions.
|
||||
remove_uncommitted_region(addr, size);
|
||||
break; // commit below
|
||||
}
|
||||
assert(rgn->contain_region(addr, size), "Must cover this region");
|
||||
return true;
|
||||
} else {
|
||||
if (rgn->end() >= addr + size){
|
||||
break;
|
||||
}
|
||||
node = node->next();
|
||||
}
|
||||
|
||||
// New committed region
|
||||
VirtualMemorySummary::record_committed_memory(size, flag());
|
||||
return add_committed_region(committed_rgn);
|
||||
}
|
||||
}
|
||||
|
||||
void ReservedMemoryRegion::set_all_committed(bool b) {
|
||||
if (all_committed() != b) {
|
||||
@ -175,48 +173,52 @@ bool ReservedMemoryRegion::remove_uncommitted_region(address addr, size_t sz) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// we have to walk whole list to remove the committed regions in
|
||||
// specified range
|
||||
LinkedListNode<CommittedMemoryRegion>* head =
|
||||
_committed_regions.head();
|
||||
LinkedListNode<CommittedMemoryRegion>* prev = NULL;
|
||||
VirtualMemoryRegion uncommitted_rgn(addr, sz);
|
||||
CommittedMemoryRegion del_rgn(addr, sz, *call_stack());
|
||||
address end = addr + sz;
|
||||
|
||||
while (head != NULL && !uncommitted_rgn.is_empty()) {
|
||||
CommittedMemoryRegion* crgn = head->data();
|
||||
// this committed region overlaps to region to uncommit
|
||||
if (crgn->overlap_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
|
||||
if (crgn->same_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
|
||||
// find matched region, remove the node will do
|
||||
VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag());
|
||||
LinkedListNode<CommittedMemoryRegion>* head = _committed_regions.head();
|
||||
LinkedListNode<CommittedMemoryRegion>* prev = NULL;
|
||||
CommittedMemoryRegion* crgn;
|
||||
|
||||
while (head != NULL) {
|
||||
crgn = head->data();
|
||||
|
||||
if (crgn->same_region(addr, sz)) {
|
||||
VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag());
|
||||
_committed_regions.remove_after(prev);
|
||||
return true;
|
||||
} else if (crgn->contain_region(uncommitted_rgn.base(), uncommitted_rgn.size())) {
|
||||
// this committed region contains whole uncommitted region
|
||||
VirtualMemorySummary::record_uncommitted_memory(uncommitted_rgn.size(), flag());
|
||||
return remove_uncommitted_region(head, uncommitted_rgn.base(), uncommitted_rgn.size());
|
||||
} else if (uncommitted_rgn.contain_region(crgn->base(), crgn->size())) {
|
||||
// this committed region has been uncommitted
|
||||
size_t exclude_size = crgn->end() - uncommitted_rgn.base();
|
||||
uncommitted_rgn.exclude_region(uncommitted_rgn.base(), exclude_size);
|
||||
}
|
||||
|
||||
// del_rgn contains crgn
|
||||
if (del_rgn.contain_region(crgn->base(), crgn->size())) {
|
||||
VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag());
|
||||
LinkedListNode<CommittedMemoryRegion>* tmp = head;
|
||||
head = head->next();
|
||||
_committed_regions.remove_after(prev);
|
||||
continue;
|
||||
} else if (crgn->contain_address(uncommitted_rgn.base())) {
|
||||
size_t toUncommitted = crgn->end() - uncommitted_rgn.base();
|
||||
crgn->exclude_region(uncommitted_rgn.base(), toUncommitted);
|
||||
uncommitted_rgn.exclude_region(uncommitted_rgn.base(), toUncommitted);
|
||||
VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag());
|
||||
} else if (uncommitted_rgn.contain_address(crgn->base())) {
|
||||
size_t toUncommitted = uncommitted_rgn.end() - crgn->base();
|
||||
crgn->exclude_region(crgn->base(), toUncommitted);
|
||||
uncommitted_rgn.exclude_region(uncommitted_rgn.end() - toUncommitted,
|
||||
toUncommitted);
|
||||
VirtualMemorySummary::record_uncommitted_memory(toUncommitted, flag());
|
||||
continue; // don't update head or prev
|
||||
}
|
||||
|
||||
// Found addr in the current crgn. There are 2 subcases:
|
||||
if (crgn->contain_address(addr)) {
|
||||
|
||||
// (1) Found addr+size in current crgn as well. (del_rgn is contained in crgn)
|
||||
if (crgn->contain_address(end - 1)) {
|
||||
VirtualMemorySummary::record_uncommitted_memory(sz, flag());
|
||||
return remove_uncommitted_region(head, addr, sz); // done!
|
||||
} else {
|
||||
// (2) Did not find del_rgn's end in crgn.
|
||||
size_t size = crgn->end() - del_rgn.base();
|
||||
crgn->exclude_region(addr, size);
|
||||
VirtualMemorySummary::record_uncommitted_memory(size, flag());
|
||||
}
|
||||
|
||||
} else if (crgn->contain_address(end - 1)) {
|
||||
// Found del_rgn's end, but not its base addr.
|
||||
size_t size = del_rgn.end() - crgn->base();
|
||||
crgn->exclude_region(crgn->base(), size);
|
||||
VirtualMemorySummary::record_uncommitted_memory(size, flag());
|
||||
return true; // should be done if the list is sorted properly!
|
||||
}
|
||||
|
||||
prev = head;
|
||||
head = head->next();
|
||||
}
|
||||
@ -386,7 +388,8 @@ bool VirtualMemoryTracker::add_committed_region(address addr, size_t size,
|
||||
|
||||
assert(reserved_rgn != NULL, "No reserved region");
|
||||
assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
|
||||
return reserved_rgn->add_committed_region(addr, size, stack);
|
||||
bool result = reserved_rgn->add_committed_region(addr, size, stack);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) {
|
||||
@ -398,7 +401,8 @@ bool VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size)
|
||||
ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn);
|
||||
assert(reserved_rgn != NULL, "No reserved region");
|
||||
assert(reserved_rgn->contain_region(addr, size), "Not completely contained");
|
||||
return reserved_rgn->remove_uncommitted_region(addr, size);
|
||||
bool result = reserved_rgn->remove_uncommitted_region(addr, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VirtualMemoryTracker::remove_released_region(address addr, size_t size) {
|
||||
@ -488,5 +492,3 @@ bool VirtualMemoryTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -261,8 +261,7 @@ class CommittedMemoryRegion : public VirtualMemoryRegion {
|
||||
VirtualMemoryRegion(addr, size), _stack(stack) { }
|
||||
|
||||
inline int compare(const CommittedMemoryRegion& rgn) const {
|
||||
if (overlap_region(rgn.base(), rgn.size()) ||
|
||||
adjacent_to (rgn.base(), rgn.size())) {
|
||||
if (overlap_region(rgn.base(), rgn.size())) {
|
||||
return 0;
|
||||
} else {
|
||||
if (base() == rgn.base()) {
|
||||
|
@ -259,6 +259,11 @@ template <class E, ResourceObj::allocation_type T = ResourceObj::C_HEAP,
|
||||
|
||||
virtual bool remove(LinkedListNode<E>* node) {
|
||||
LinkedListNode<E>* p = this->head();
|
||||
if (p == node) {
|
||||
this->set_head(p->next());
|
||||
delete_node(node);
|
||||
return true;
|
||||
}
|
||||
while (p != NULL && p->next() != node) {
|
||||
p = p->next();
|
||||
}
|
||||
|
144
hotspot/test/runtime/NMT/CommitOverlappingRegions.java
Normal file
144
hotspot/test/runtime/NMT/CommitOverlappingRegions.java
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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
|
||||
* @summary Test commits of overlapping regions of memory.
|
||||
* @key nmt jcmd
|
||||
* @library /testlibrary /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build CommitOverlappingRegions
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail CommitOverlappingRegions
|
||||
*/
|
||||
|
||||
import jdk.test.lib.*;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public class CommitOverlappingRegions {
|
||||
public static WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
public static void main(String args[]) throws Exception {
|
||||
OutputAnalyzer output;
|
||||
long size = 32 * 1024;
|
||||
long addr = wb.NMTReserveMemory(8*size);
|
||||
|
||||
String pid = Long.toString(ProcessTools.getProcessId());
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "detail"});
|
||||
System.out.println("Address is " + Long.toHexString(addr));
|
||||
|
||||
// Start: . . . . . . . .
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=0KB)");
|
||||
|
||||
// Committing: * * * . . . . .
|
||||
// Region: * * * . . . . .
|
||||
// Expected Total: 3 x 32KB = 96KB
|
||||
wb.NMTCommitMemory(addr + 0*size, 3*size);
|
||||
|
||||
// Committing: . . . . * * * .
|
||||
// Region: * * * . * * * .
|
||||
// Expected Total: 6 x 32KB = 192KB
|
||||
wb.NMTCommitMemory(addr + 4*size, 3*size);
|
||||
|
||||
// Check output after first 2 commits.
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=192KB)");
|
||||
|
||||
// Committing: . . * * * . . .
|
||||
// Region: * * * * * * * .
|
||||
// Expected Total: 7 x 32KB = 224KB
|
||||
wb.NMTCommitMemory(addr + 2*size, 3*size);
|
||||
|
||||
// Check output after overlapping commit.
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=224KB)");
|
||||
|
||||
// Uncommitting: * * * * * * * *
|
||||
// Region: . . . . . . . .
|
||||
// Expected Total: 0 x 32KB = 0KB
|
||||
wb.NMTUncommitMemory(addr + 0*size, 8*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=0KB)");
|
||||
|
||||
// Committing: * * . . . . . .
|
||||
// Region: * * . . . . . .
|
||||
// Expected Total: 2 x 32KB = 64KB
|
||||
wb.NMTCommitMemory(addr + 0*size, 2*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=64KB)");
|
||||
|
||||
// Committing: . * * * . . . .
|
||||
// Region: * * * * . . . .
|
||||
// Expected Total: 4 x 32KB = 128KB
|
||||
wb.NMTCommitMemory(addr + 1*size, 3*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=128KB)");
|
||||
|
||||
// Uncommitting: * * * . . . . .
|
||||
// Region: . . . * . . . .
|
||||
// Expected Total: 1 x 32KB = 32KB
|
||||
wb.NMTUncommitMemory(addr + 0*size, 3*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=32KB)");
|
||||
|
||||
// Committing: . . . * * . . .
|
||||
// Region: . . . * * . . .
|
||||
// Expected Total: 2 x 32KB = 64KB
|
||||
wb.NMTCommitMemory(addr + 3*size, 2*size);
|
||||
System.out.println("Address is " + Long.toHexString(addr + 3*size));
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=64KB)");
|
||||
|
||||
// Committing: . . . . * * . .
|
||||
// Region: . . . * * * . .
|
||||
// Expected Total: 3 x 32KB = 96KB
|
||||
wb.NMTCommitMemory(addr + 4*size, 2*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=96KB)");
|
||||
|
||||
// Committing: . . . . . * * .
|
||||
// Region: . . . * * * * .
|
||||
// Expected Total: 4 x 32KB = 128KB
|
||||
wb.NMTCommitMemory(addr + 5*size, 2*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=128KB)");
|
||||
|
||||
// Committing: . . . . . . * *
|
||||
// Region: . . . * * * * *
|
||||
// Expected Total: 5 x 32KB = 160KB
|
||||
wb.NMTCommitMemory(addr + 6*size, 2*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=160KB)");
|
||||
|
||||
// Uncommitting: * * * * * * * *
|
||||
// Region: . . . . . . . .
|
||||
// Expected Total: 0 x 32KB = 32KB
|
||||
wb.NMTUncommitMemory(addr + 0*size, 8*size);
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("Test (reserved=256KB, committed=0KB)");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user