< prev index next >

src/hotspot/share/services/virtualMemoryTracker.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, 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.

@@ -46,61 +46,109 @@
 
 int compare_reserved_region_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) {
   return r1.compare(r2);
 }
 
-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");
+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);
+}
 
-  if (all_committed()) return true;
+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);
+}
 
-  CommittedMemoryRegion committed_rgn(addr, size, stack);
-  LinkedListNode<CommittedMemoryRegion>* node = _committed_regions.head();
+static LinkedListNode<CommittedMemoryRegion>* find_preceding_node_from(LinkedListNode<CommittedMemoryRegion>* from, address addr) {
+  LinkedListNode<CommittedMemoryRegion>* preceding = NULL;
 
-  while (node != NULL) {
+  for (LinkedListNode<CommittedMemoryRegion>* node = from; node != NULL; node = node->next()) {
     CommittedMemoryRegion* rgn = node->data();
-    if (rgn->same_region(addr, size)) {
-      return true;
+
+    // We searched past the region start.
+    if (rgn->end() > addr) {
+      break;
     }
 
-    if (rgn->adjacent_to(addr, size)) {
-      // 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
+    preceding = node;
+  }
+
+  return preceding;
+}
+
+static bool try_merge_with(LinkedListNode<CommittedMemoryRegion>* node, address addr, size_t size, const NativeCallStack& stack) {
+  if (node != NULL) {
+    CommittedMemoryRegion* rgn = node->data();
+
+    if (is_mergeable_with(rgn, addr, size, stack)) {
         rgn->expand_region(addr, size);
-        VirtualMemorySummary::record_committed_memory(rgn->size(), flag());
         return true;
       }
       }
 
-    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
+  return false;
+}
+
+static bool try_merge_with(LinkedListNode<CommittedMemoryRegion>* node, LinkedListNode<CommittedMemoryRegion>* other) {
+  if (other == NULL) {
+    return false;
     }
-    if (rgn->end() >= addr + size){
-      break;
+
+  CommittedMemoryRegion* rgn = other->data();
+  return try_merge_with(node, rgn->base(), rgn->size(), *rgn->call_stack());
+}
+
+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");
+
+  // Find the region that fully precedes the [addr, addr + size) region.
+  LinkedListNode<CommittedMemoryRegion>* prev = find_preceding_node_from(_committed_regions.head(), addr);
+  LinkedListNode<CommittedMemoryRegion>* next = (prev != NULL ? prev->next() : _committed_regions.head());
+
+  if (next != NULL) {
+    // Ignore request if region already exists.
+    if (is_same_as(next->data(), addr, size, stack)) {
+      return true;
+    }
+
+    // The new region is after prev, and either overlaps with the
+    // next region (and maybe more regions), or overlaps with no region.
+    if (next->data()->overlap_region(addr, size)) {
+      // Remove _all_ overlapping regions, and parts of regions,
+      // in preparation for the addition of this new region.
+      remove_uncommitted_region(addr, size);
+
+      // The remove could have split a region into two and created a
+      // new prev region. Need to reset the prev and next pointers.
+      prev = find_preceding_node_from((prev != NULL ? prev : _committed_regions.head()), addr);
+      next = (prev != NULL ? prev->next() : _committed_regions.head());
     }
-    node = node->next();
   }
 
-    // New committed region
+  // At this point the previous overlapping regions have been
+  // cleared, and the full region is guaranteed to be inserted.
     VirtualMemorySummary::record_committed_memory(size, flag());
-    return add_committed_region(committed_rgn);
+
+  // Try to merge with prev and possibly next.
+  if (try_merge_with(prev, addr, size, stack)) {
+    if (try_merge_with(prev, next)) {
+      // prev was expanded to contain the new region
+      // and next, need to remove next from the list
+      _committed_regions.remove_after(prev);
   }
 
-void ReservedMemoryRegion::set_all_committed(bool b) {
-  if (all_committed() != b) {
-    _all_committed = b;
-    if (b) {
-      VirtualMemorySummary::record_committed_memory(size(), flag());
+    return true;
     }
+
+  // Didn't merge with prev, try with next.
+  if (try_merge_with(next, addr, size, stack)) {
+    return true;
   }
+
+  // Couldn't merge with any regions - create a new region.
+  return add_committed_region(CommittedMemoryRegion(addr, size, stack));
 }
 
 bool ReservedMemoryRegion::remove_uncommitted_region(LinkedListNode<CommittedMemoryRegion>* node,
   address addr, size_t size) {
   assert(addr != NULL, "Invalid address");

@@ -133,49 +181,13 @@
 
   return false;
 }
 
 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)) {
-      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<CommittedMemoryRegion>* head = _committed_regions.head();
     LinkedListNode<CommittedMemoryRegion>* prev = NULL;

@@ -221,11 +233,10 @@
       }
 
       prev = head;
       head = head->next();
     }
-  }
 
   return true;
 }
 
 void ReservedMemoryRegion::move_committed_regions(address addr, ReservedMemoryRegion& rgn) {

@@ -254,22 +265,18 @@
 
   rgn._committed_regions.set_head(head);
 }
 
 size_t ReservedMemoryRegion::committed_size() const {
-  if (all_committed()) {
-    return size();
-  } else {
     size_t committed = 0;
     LinkedListNode<CommittedMemoryRegion>* head =
       _committed_regions.head();
     while (head != NULL) {
       committed += head->data()->size();
       head = head->next();
     }
     return committed;
-  }
 }
 
 void ReservedMemoryRegion::set_flag(MEMFLAGS f) {
   assert((flag() == mtNone || flag() == f), "Overwrite memory type");
   if (flag() != f) {

@@ -294,26 +301,20 @@
   }
   return true;
 }
 
 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<ReservedMemoryRegion>* 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);
       reserved_rgn->set_flag(flag);
       return true;
< prev index next >