OSDN Git Service

Add more detail to rosalloc fragmentation OOME
authorMathieu Chartier <mathieuc@google.com>
Fri, 2 Dec 2016 01:41:17 +0000 (17:41 -0800)
committerMathieu Chartier <mathieuc@google.com>
Fri, 2 Dec 2016 19:55:39 +0000 (11:55 -0800)
Also include total number of free page bytes, space footprint, and
space max capacity.

Sample output:
Throwing OutOfMemoryError "Failed to allocate a 7012 byte allocation
with 103464 free bytes and 101KB until OOM; failed due to
fragmentation (required continguous free 8192 bytes, largest
contiguous free 4096 bytes, total free pages 4096 bytes, space
footprint 268435456 bytes, space max capacity 268435456 bytes)

Added a basic test to ensure the allocator coalesces properly.

Bug: 32997082

Test: test-art-host

Change-Id: I642b6ad34b98f6d98c10f242a6f6e926e0b42acc

runtime/gc/allocator/rosalloc.cc
runtime/gc/heap.cc
test/080-oom-fragmentation/expected.txt [new file with mode: 0644]
test/080-oom-fragmentation/info.txt [new file with mode: 0644]
test/080-oom-fragmentation/src/Main.java [new file with mode: 0644]

index 40186f8..2e4475f 100644 (file)
@@ -2068,26 +2068,30 @@ void RosAlloc::LogFragmentationAllocFailure(std::ostream& os, size_t failed_allo
   size_t largest_continuous_free_pages = 0;
   WriterMutexLock wmu(self, bulk_free_lock_);
   MutexLock mu(self, lock_);
+  uint64_t total_free = 0;
   for (FreePageRun* fpr : free_page_runs_) {
     largest_continuous_free_pages = std::max(largest_continuous_free_pages,
                                              fpr->ByteSize(this));
+    total_free += fpr->ByteSize(this);
   }
+  size_t required_bytes = 0;
+  const char* new_buffer_msg = "";
   if (failed_alloc_bytes > kLargeSizeThreshold) {
     // Large allocation.
-    size_t required_bytes = RoundUp(failed_alloc_bytes, kPageSize);
-    if (required_bytes > largest_continuous_free_pages) {
-      os << "; failed due to fragmentation (required continguous free "
-         << required_bytes << " bytes where largest contiguous free "
-         <<  largest_continuous_free_pages << " bytes)";
-    }
+    required_bytes = RoundUp(failed_alloc_bytes, kPageSize);
   } else {
     // Non-large allocation.
-    size_t required_bytes = numOfPages[SizeToIndex(failed_alloc_bytes)] * kPageSize;
-    if (required_bytes > largest_continuous_free_pages) {
-      os << "; failed due to fragmentation (required continguous free "
-         << required_bytes << " bytes for a new buffer where largest contiguous free "
-         <<  largest_continuous_free_pages << " bytes)";
-    }
+    required_bytes = numOfPages[SizeToIndex(failed_alloc_bytes)] * kPageSize;
+    new_buffer_msg = " for a new buffer";
+  }
+  if (required_bytes > largest_continuous_free_pages) {
+    os << "; failed due to fragmentation ("
+       << "required contiguous free " << required_bytes << " bytes" << new_buffer_msg
+       << ", largest contiguous free " << largest_continuous_free_pages << " bytes"
+       << ", total free pages " << total_free << " bytes"
+       << ", space footprint " << footprint_ << " bytes"
+       << ", space max capacity " << max_capacity_ << " bytes"
+       << ")" << std::endl;
   }
 }
 
index 5c219cc..8ff5e5a 100644 (file)
@@ -1326,7 +1326,9 @@ void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType
   std::ostringstream oss;
   size_t total_bytes_free = GetFreeMemory();
   oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
-      << " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM";
+      << " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM,"
+      << " max allowed footprint " << max_allowed_footprint_ << ", growth limit "
+      << growth_limit_;
   // If the allocation failed due to fragmentation, print out the largest continuous allocation.
   if (total_bytes_free >= byte_count) {
     space::AllocSpace* space = nullptr;
diff --git a/test/080-oom-fragmentation/expected.txt b/test/080-oom-fragmentation/expected.txt
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/080-oom-fragmentation/info.txt b/test/080-oom-fragmentation/info.txt
new file mode 100644 (file)
index 0000000..5bcc425
--- /dev/null
@@ -0,0 +1,2 @@
+Test that the allocator can go from a full heap to an empty one and is able to allocate a large
+object array.
diff --git a/test/080-oom-fragmentation/src/Main.java b/test/080-oom-fragmentation/src/Main.java
new file mode 100644 (file)
index 0000000..cf21139
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+        // Reserve around 1/4 of the RAM for keeping objects live.
+        long maxMem = Runtime.getRuntime().maxMemory();
+        Object[] holder = new Object[(int)maxMem / 16];
+        int count = 0;
+        try {
+            while (true) {
+                holder[count++] = new Object[1025];  // A bit over one page.
+            }
+        } catch (OutOfMemoryError e) {}
+        for (int i = 0; i < count; ++i) {
+            holder[i] = null;
+        }
+        // Make sure the heap can handle allocating large object array. This makes sure that free
+        // pages are correctly coalesced together by the allocator.
+        holder[0] = new Object[(int)maxMem / 8];
+    }
+}