--- old/src/hotspot/share/services/virtualMemoryTracker.cpp 2018-02-15 14:25:51.132091472 +0100 +++ new/src/hotspot/share/services/virtualMemoryTracker.cpp 2018-02-15 14:25:50.936084826 +0100 @@ -48,57 +48,92 @@ return r1.compare(r2); } +static bool is_mergeable_with(CommittedMemoryRegion* rgn, address addr, size_t size, const NativeCallStack& stack) { + return rgn->adjacent_to(addr, size) && rgn->call_stack()->equals(stack); +} + +static bool is_same_as(CommittedMemoryRegion* rgn, address addr, size_t size, const NativeCallStack& stack) { + // It would have made sense to use rgn->equals(...), but equals returns true for overlapping regions. + return rgn->same_region(addr, size) && rgn->call_stack()->equals(stack); +} + +void ReservedMemoryRegion::merge_with(LinkedListNode* node, address addr, size_t size, const NativeCallStack& stack) { + CommittedMemoryRegion* rgn = node->data(); + assert(rgn->call_stack()->equals(stack), "Stack mismatch"); + assert(rgn->adjacent_to(addr, size), "Not adjacent"); + + rgn->expand_region(addr, size); + + LinkedListNode* next = node->next(); + if (next != NULL) { + address next_addr = next->data()->base(); + size_t next_size = next->data()->size(); + const NativeCallStack& next_stack = *next->data()->call_stack(); + + if (is_mergeable_with(rgn, next_addr, next_size, next_stack)) { + rgn->expand_region(next_addr, next_size); + _committed_regions.remove(next); + } + } +} + bool ReservedMemoryRegion::add_committed_region(address addr, size_t size, const NativeCallStack& stack) { assert(addr != NULL, "Invalid address"); assert(size > 0, "Invalid size"); assert(contain_region(addr, size), "Not contain this region"); - if (all_committed()) return true; - - CommittedMemoryRegion committed_rgn(addr, size, stack); - LinkedListNode* node = _committed_regions.head(); + LinkedListNode* prev = NULL; - while (node != NULL) { + for (LinkedListNode* node = _committed_regions.head(); + node != NULL; + node = node->next()) { CommittedMemoryRegion* rgn = node->data(); - if (rgn->same_region(addr, size)) { + + // Ignore request if region already exists. + if (is_same_as(rgn, addr, size, stack)) { return true; } - if (rgn->adjacent_to(addr, size)) { - // special case to expand prior region if there is no next region - LinkedListNode* 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; - } - } - + // Found an overlapping region + // - remove _all_ overlapping regions in preparation + // for the addition of this new region. 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 + break; } - if (rgn->end() >= addr + size){ + + // We searched past this new region. + if (rgn->base() >= addr + size) { break; } - node = node->next(); - } - // New committed region - VirtualMemorySummary::record_committed_memory(size, flag()); - return add_committed_region(committed_rgn); + prev = node; } -void ReservedMemoryRegion::set_all_committed(bool b) { - if (all_committed() != b) { - _all_committed = b; - if (b) { - VirtualMemorySummary::record_committed_memory(size(), flag()); + // At this point the previous overlapping regions have been + // cleared, and the full region guaranteed to be inserted. + VirtualMemorySummary::record_committed_memory(size, flag()); + + // Try to merge if possible. + + // Preceding node might be prev, or a node created by remove_uncommitted_region. + for (LinkedListNode* node = (prev != NULL) ? prev : _committed_regions.head(); + node != NULL; + node = node->next()) { + CommittedMemoryRegion* rgn = node->data(); + + if (is_mergeable_with(rgn, addr, size, stack)) { + merge_with(node, addr, size, stack); + return true; + } + + if (rgn->base() >= addr + size) { + break; } } + + // Couldn't merge with any regions - create a new region. + return add_committed_region(CommittedMemoryRegion(addr, size, stack)); } bool ReservedMemoryRegion::remove_uncommitted_region(LinkedListNode* node, @@ -135,94 +170,57 @@ } bool ReservedMemoryRegion::remove_uncommitted_region(address addr, size_t sz) { - // uncommit stack guard pages - if (flag() == mtThreadStack && !same_region(addr, sz)) { - return true; - } - assert(addr != NULL, "Invalid address"); assert(sz > 0, "Invalid size"); - if (all_committed()) { - assert(_committed_regions.is_empty(), "Sanity check"); - assert(contain_region(addr, sz), "Reserved region does not contain this region"); - set_all_committed(false); - VirtualMemorySummary::record_uncommitted_memory(sz, flag()); - if (same_region(addr, sz)) { + CommittedMemoryRegion del_rgn(addr, sz, *call_stack()); + address end = addr + sz; + + LinkedListNode* head = _committed_regions.head(); + LinkedListNode* 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 { - CommittedMemoryRegion rgn(base(), size(), *call_stack()); - if (rgn.base() == addr || rgn.end() == (addr + sz)) { - rgn.exclude_region(addr, sz); - return add_committed_region(rgn); - } else { - // split this region - // top of the whole region - address top =rgn.end(); - // use this region for lower part - size_t exclude_size = rgn.end() - addr; - rgn.exclude_region(addr, exclude_size); - if (add_committed_region(rgn)) { - // higher part - address high_base = addr + sz; - size_t high_size = top - high_base; - CommittedMemoryRegion high_rgn(high_base, high_size, NativeCallStack::EMPTY_STACK); - return add_committed_region(high_rgn); - } else { - return false; - } - } } - } else { - CommittedMemoryRegion del_rgn(addr, sz, *call_stack()); - address end = addr + sz; - LinkedListNode* head = _committed_regions.head(); - LinkedListNode* 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; - } + // del_rgn contains crgn + if (del_rgn.contain_region(crgn->base(), crgn->size())) { + VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag()); + head = head->next(); + _committed_regions.remove_after(prev); + continue; // don't update head or prev + } - // del_rgn contains crgn - if (del_rgn.contain_region(crgn->base(), crgn->size())) { - VirtualMemorySummary::record_uncommitted_memory(crgn->size(), flag()); - head = head->next(); - _committed_regions.remove_after(prev); - 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()); - } + // Found addr in the current crgn. There are 2 subcases: + if (crgn->contain_address(addr)) { - } 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); + // (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()); - return true; // should be done if the list is sorted properly! } - prev = head; - head = head->next(); + } 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(); } return true; @@ -256,18 +254,14 @@ } size_t ReservedMemoryRegion::committed_size() const { - if (all_committed()) { - return size(); - } else { - size_t committed = 0; - LinkedListNode* head = - _committed_regions.head(); - while (head != NULL) { - committed += head->data()->size(); - head = head->next(); - } - return committed; + size_t committed = 0; + LinkedListNode* head = + _committed_regions.head(); + while (head != NULL) { + committed += head->data()->size(); + head = head->next(); } + return committed; } void ReservedMemoryRegion::set_flag(MEMFLAGS f) { @@ -296,22 +290,16 @@ } bool VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, - const NativeCallStack& stack, MEMFLAGS flag, bool all_committed) { + const NativeCallStack& stack, MEMFLAGS flag) { assert(base_addr != NULL, "Invalid address"); assert(size > 0, "Invalid size"); assert(_reserved_regions != NULL, "Sanity check"); ReservedMemoryRegion rgn(base_addr, size, stack, flag); ReservedMemoryRegion* reserved_rgn = _reserved_regions->find(rgn); - LinkedListNode* node; + if (reserved_rgn == NULL) { VirtualMemorySummary::record_reserved_memory(size, flag); - node = _reserved_regions->add(rgn); - if (node != NULL) { - node->data()->set_all_committed(all_committed); - return true; - } else { - return false; - } + return _reserved_regions->add(rgn) != NULL; } else { if (reserved_rgn->same_region(base_addr, size)) { reserved_rgn->set_call_stack(stack);