summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Hiroshi Yamauchi <yamauchi@google.com> 2014-07-09 12:54:32 -0700
committer Hiroshi Yamauchi <yamauchi@google.com> 2014-07-10 10:50:04 -0700
commit654dd48e2230e16bfaa225decce72b52642e2f78 (patch)
treeaf06c5db6159159ffd701c0bbd43440e86ddf1fb
parentadce33da293b0eeaaf52673338770f22be71ca5d (diff)
Improve the OOME fragmentation message.
Change-Id: I390d3622f8d572ec7e34ea6dff9e1e0936e81ac1
-rw-r--r--runtime/gc/allocator/rosalloc.cc28
-rw-r--r--runtime/gc/allocator/rosalloc.h2
-rw-r--r--runtime/gc/heap.cc38
-rw-r--r--runtime/gc/heap.h3
-rw-r--r--runtime/gc/space/dlmalloc_space.cc24
-rw-r--r--runtime/gc/space/dlmalloc_space.h3
-rw-r--r--runtime/gc/space/malloc_space.h3
-rw-r--r--runtime/gc/space/rosalloc_space.h4
8 files changed, 77 insertions, 28 deletions
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 722576f164..d26635faf3 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -2175,6 +2175,34 @@ size_t RosAlloc::ReleasePageRange(byte* start, byte* end) {
return reclaimed_bytes;
}
+void RosAlloc::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) {
+ Thread* self = Thread::Current();
+ size_t largest_continuous_free_pages = 0;
+ WriterMutexLock wmu(self, bulk_free_lock_);
+ MutexLock mu(self, lock_);
+ for (FreePageRun* fpr : free_page_runs_) {
+ largest_continuous_free_pages = std::max(largest_continuous_free_pages,
+ fpr->ByteSize(this));
+ }
+ 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)";
+ }
+ } 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)";
+ }
+ }
+}
+
} // namespace allocator
} // namespace gc
} // namespace art
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index fad0dc888e..85a8225807 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -590,6 +590,8 @@ class RosAlloc {
// Verify for debugging.
void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes);
};
} // namespace allocator
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index e9adca07c6..19715e9331 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -805,37 +805,23 @@ space::ImageSpace* Heap::GetImageSpace() const {
return NULL;
}
-static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
- size_t chunk_size = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start);
- if (used_bytes < chunk_size) {
- size_t chunk_free_bytes = chunk_size - used_bytes;
- size_t& max_contiguous_allocation = *reinterpret_cast<size_t*>(arg);
- max_contiguous_allocation = std::max(max_contiguous_allocation, chunk_free_bytes);
- }
-}
-
-void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation) {
+void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type) {
std::ostringstream oss;
size_t total_bytes_free = GetFreeMemory();
oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
<< " free bytes";
// If the allocation failed due to fragmentation, print out the largest continuous allocation.
- if (!large_object_allocation && total_bytes_free >= byte_count) {
- size_t max_contiguous_allocation = 0;
- for (const auto& space : continuous_spaces_) {
- if (space->IsMallocSpace()) {
- // To allow the Walk/InspectAll() to exclusively-lock the mutator
- // lock, temporarily release the shared access to the mutator
- // lock here by transitioning to the suspended state.
- Locks::mutator_lock_->AssertSharedHeld(self);
- self->TransitionFromRunnableToSuspended(kSuspended);
- space->AsMallocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
- self->TransitionFromSuspendedToRunnable();
- Locks::mutator_lock_->AssertSharedHeld(self);
- }
+ if (allocator_type != kAllocatorTypeLOS && total_bytes_free >= byte_count) {
+ space::MallocSpace* space = nullptr;
+ if (allocator_type == kAllocatorTypeNonMoving) {
+ space = non_moving_space_;
+ } else if (allocator_type == kAllocatorTypeRosAlloc ||
+ allocator_type == kAllocatorTypeDlMalloc) {
+ space = main_space_;
+ }
+ if (space != nullptr) {
+ space->LogFragmentationAllocFailure(oss, byte_count);
}
- oss << "; failed due to fragmentation (largest possible contiguous allocation "
- << max_contiguous_allocation << " bytes)";
}
self->ThrowOutOfMemoryError(oss.str().c_str());
}
@@ -1188,7 +1174,7 @@ mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocat
}
ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated, usable_size);
if (ptr == nullptr) {
- ThrowOutOfMemoryError(self, alloc_size, allocator == kAllocatorTypeLOS);
+ ThrowOutOfMemoryError(self, alloc_size, allocator);
}
return ptr;
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index c9ea03e45c..07db169f3a 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -194,7 +194,6 @@ class Heap {
void CheckPreconditionsForAllocObject(mirror::Class* c, size_t byte_count)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void ThrowOutOfMemoryError(size_t byte_count, bool large_object_allocation);
void RegisterNativeAllocation(JNIEnv* env, int bytes);
void RegisterNativeFree(JNIEnv* env, int bytes);
@@ -628,7 +627,7 @@ class Heap {
size_t* usable_size)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation)
+ void ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template <bool kGrow>
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 5123e4787d..456d1b31e2 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -304,6 +304,30 @@ void DlMallocSpace::CheckMoreCoreForPrecondition() {
}
#endif
+static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
+ size_t chunk_size = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start);
+ if (used_bytes < chunk_size) {
+ size_t chunk_free_bytes = chunk_size - used_bytes;
+ size_t& max_contiguous_allocation = *reinterpret_cast<size_t*>(arg);
+ max_contiguous_allocation = std::max(max_contiguous_allocation, chunk_free_bytes);
+ }
+}
+
+void DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) {
+ Thread* self = Thread::Current();
+ size_t max_contiguous_allocation = 0;
+ // To allow the Walk/InspectAll() to exclusively-lock the mutator
+ // lock, temporarily release the shared access to the mutator
+ // lock here by transitioning to the suspended state.
+ Locks::mutator_lock_->AssertSharedHeld(self);
+ self->TransitionFromRunnableToSuspended(kSuspended);
+ Walk(MSpaceChunkCallback, &max_contiguous_allocation);
+ self->TransitionFromSuspendedToRunnable();
+ Locks::mutator_lock_->AssertSharedHeld(self);
+ os << "; failed due to fragmentation (largest possible contiguous allocation "
+ << max_contiguous_allocation << " bytes)";
+}
+
} // namespace space
} // namespace gc
} // namespace art
diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h
index accd26bd21..7aff14b665 100644
--- a/runtime/gc/space/dlmalloc_space.h
+++ b/runtime/gc/space/dlmalloc_space.h
@@ -124,6 +124,9 @@ class DlMallocSpace : public MallocSpace {
return this;
}
+ void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) OVERRIDE
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
protected:
DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin, byte* end,
byte* limit, size_t growth_limit, bool can_move_objects, size_t starting_size,
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index d24016cb18..6f49fbf203 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -19,6 +19,7 @@
#include "space.h"
+#include <iostream>
#include <valgrind.h>
#include <memcheck/memcheck.h>
@@ -132,6 +133,8 @@ class MallocSpace : public ContinuousMemMapAllocSpace {
return can_move_objects_;
}
+ virtual void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) = 0;
+
protected:
MallocSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end,
byte* limit, size_t growth_limit, bool create_bitmaps, bool can_move_objects,
diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h
index 2934af87c6..f50530576b 100644
--- a/runtime/gc/space/rosalloc_space.h
+++ b/runtime/gc/space/rosalloc_space.h
@@ -120,6 +120,10 @@ class RosAllocSpace : public MallocSpace {
virtual ~RosAllocSpace();
+ void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) OVERRIDE {
+ rosalloc_->LogFragmentationAllocFailure(os, failed_alloc_bytes);
+ }
+
protected:
RosAllocSpace(const std::string& name, MemMap* mem_map, allocator::RosAlloc* rosalloc,
byte* begin, byte* end, byte* limit, size_t growth_limit, bool can_move_objects,