< prev index next >

src/hotspot/share/gc/z/zPageAllocator.cpp

Print this page

        

@@ -126,10 +126,13 @@
     _used_low(0),
     _allocated(0),
     _reclaimed(0),
     _stalled(),
     _satisfied(),
+    _unmap_lock(),
+    _unmap_queue(),
+    _unmap_stop(false),
     _uncommit_lock(),
     _uncommit_enabled(false),
     _uncommit_stop(false),
     _safe_delete(),
     _initialized(false) {

@@ -360,16 +363,16 @@
   _physical.uncommit(page->physical_memory());
 }
 
 bool ZPageAllocator::map_page(const ZPage* page) const {
   // Map physical memory
-  return _physical.map(page->physical_memory(), page->start());
+  return _physical.map(page->start(), page->physical_memory());
 }
 
 void ZPageAllocator::unmap_page(const ZPage* page) const {
   // Unmap physical memory
-  _physical.unmap(page->physical_memory(), page->start());
+  _physical.unmap(page->start(), page->size());
 }
 
 void ZPageAllocator::destroy_page(ZPage* page) {
   // Free virtual memory
   _virtual.free(page->virtual_memory());

@@ -379,10 +382,33 @@
 
   // Delete page safely
   _safe_delete(page);
 }
 
+void ZPageAllocator::enqueue_unmap_page(ZPage* page) {
+  ZLocker<ZConditionLock> locker(&_unmap_lock);
+  _unmap_queue.insert_last(page);
+  _unmap_lock.notify_all();
+}
+
+ZPage* ZPageAllocator::dequeue_unmap_page() {
+  ZLocker<ZConditionLock> locker(&_unmap_lock);
+
+  for (;;) {
+    if (_unmap_stop) {
+      return NULL;
+    }
+
+    ZPage* const page = _unmap_queue.remove_first();
+    if (page != NULL) {
+      return page;
+    }
+
+    _unmap_lock.wait();
+  }
+}
+
 bool ZPageAllocator::is_alloc_allowed(size_t size, bool no_reserve) const {
   size_t available = _current_max_capacity - _used - _claimed;
 
   if (no_reserve) {
     // The reserve should not be considered available

@@ -529,26 +555,27 @@
 ZPage* ZPageAllocator::alloc_page_create(ZPageAllocation* allocation) {
   const size_t size = allocation->size();
 
   // Allocate virtual memory. To make error handling a lot more straight
   // forward, we allocate virtual memory before destroying flushed pages.
+  // Flushed pages are also unmapped and destroyed asynchronously, so we
+  // can't immediately reuse that part of the address space anyway.
   const ZVirtualMemory vmem = _virtual.alloc(size, allocation->flags().low_address());
   if (vmem.is_null()) {
     log_error(gc)("Out of address space");
     return NULL;
   }
 
   ZPhysicalMemory pmem;
   size_t flushed = 0;
 
-  // Unmap, transfer physical memory, and destroy flushed pages
+  // Transfer physical memory, and enqueue pages for unmap and destroy
   ZListRemoveIterator<ZPage> iter(allocation->pages());
   for (ZPage* page; iter.next(&page);) {
     flushed += page->size();
-    unmap_page(page);
     pmem.transfer_segments(page->physical_memory());
-    destroy_page(page);
+    enqueue_unmap_page(page);
   }
 
   if (flushed > 0) {
     // Update statistics
     ZStatInc(ZCounterPageCacheFlush, flushed);

@@ -717,10 +744,30 @@
 
   // Try satisfy stalled allocations
   satisfy_stalled();
 }
 
+void ZPageAllocator::unmap_run() {
+  for (;;) {
+    ZPage* const page = dequeue_unmap_page();
+    if (page == NULL) {
+      // Stop
+      return;
+    }
+
+    // Unmap and destroy page
+    unmap_page(page);
+    destroy_page(page);
+  }
+}
+
+void ZPageAllocator::unmap_stop() {
+  ZLocker<ZConditionLock> locker(&_unmap_lock);
+  _unmap_stop = true;
+  _unmap_lock.notify_all();
+}
+
 size_t ZPageAllocator::uncommit(uint64_t* timeout) {
   // We need to join the suspendible thread set while manipulating capacity and
   // used, to make sure GC safepoints will have a consistent view. However, when
   // ZVerifyViews is enabled we need to join at a broader scope to also make sure
   // we don't change the address good mask after pages have been flushed, and

@@ -848,29 +895,34 @@
   _safe_delete.disable_deferred_delete();
 }
 
 void ZPageAllocator::debug_map_page(const ZPage* page) const {
   assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
-  _physical.debug_map(page->physical_memory(), page->start());
+  _physical.debug_map(page->start(), page->physical_memory());
 }
 
 void ZPageAllocator::debug_unmap_page(const ZPage* page) const {
   assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
-  _physical.debug_unmap(page->physical_memory(), page->start());
+  _physical.debug_unmap(page->start(), page->size());
 }
 
 void ZPageAllocator::pages_do(ZPageClosure* cl) const {
   assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
 
-  ZListIterator<ZPageAllocation> iter(&_satisfied);
-  for (ZPageAllocation* allocation; iter.next(&allocation);) {
-    ZListIterator<ZPage> iter(allocation->pages());
-    for (ZPage* page; iter.next(&page);) {
+  ZListIterator<ZPageAllocation> iter_satisfied(&_satisfied);
+  for (ZPageAllocation* allocation; iter_satisfied.next(&allocation);) {
+    ZListIterator<ZPage> iter_pages(allocation->pages());
+    for (ZPage* page; iter_pages.next(&page);) {
       cl->do_page(page);
     }
   }
 
+  ZListIterator<ZPage> iter_unmap_queue(&_unmap_queue);
+  for (ZPage* page; iter_unmap_queue.next(&page);) {
+    cl->do_page(page);
+  }
+
   _cache.pages_do(cl);
 }
 
 bool ZPageAllocator::is_alloc_stalled() const {
   assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
< prev index next >