Improved OOME detail messages.
Example (from logcat):
Throwing OutOfMemoryError "Failed to allocate a 1036-byte byte[] (143176 total bytes free; largest possible contiguous allocation 976 bytes)"
Change-Id: I4c83cafef775aa0590613f26080981eae5ce7da4
diff --git a/src/heap.cc b/src/heap.cc
index e244cf1..eb62807 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -267,24 +267,49 @@
delete lock_;
}
-Object* Heap::AllocObject(Class* klass, size_t byte_count) {
+static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
+ size_t& max_contiguous_allocation = *reinterpret_cast<size_t*>(arg);
+
+ size_t chunk_size = static_cast<size_t>(reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start));
+ size_t chunk_free_bytes = 0;
+ if (used_bytes < chunk_size) {
+ chunk_free_bytes = chunk_size - used_bytes;
+ }
+
+ if (chunk_free_bytes > max_contiguous_allocation) {
+ max_contiguous_allocation = chunk_free_bytes;
+ }
+}
+
+Object* Heap::AllocObject(Class* c, size_t byte_count) {
+ // Used in the detail message if we throw an OOME.
+ int64_t total_bytes_free;
+ size_t max_contiguous_allocation;
+
{
ScopedHeapLock heap_lock;
- DCHECK(klass == NULL || (klass->IsClassClass() && byte_count >= sizeof(Class)) ||
- (klass->IsVariableSize() || klass->GetObjectSize() == byte_count) ||
- strlen(ClassHelper(klass).GetDescriptor()) == 0);
+ DCHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(Class)) ||
+ (c->IsVariableSize() || c->GetObjectSize() == byte_count) ||
+ strlen(ClassHelper(c).GetDescriptor()) == 0);
DCHECK_GE(byte_count, sizeof(Object));
Object* obj = AllocateLocked(byte_count);
if (obj != NULL) {
- obj->SetClass(klass);
+ obj->SetClass(c);
if (Dbg::IsAllocTrackingEnabled()) {
- Dbg::RecordAllocation(klass, byte_count);
+ Dbg::RecordAllocation(c, byte_count);
}
return obj;
}
+ total_bytes_free = GetFreeMemory();
+ max_contiguous_allocation = 0;
+ GetAllocSpace()->Walk(MSpaceChunkCallback, &max_contiguous_allocation);
}
- Thread::Current()->ThrowOutOfMemoryError(klass, byte_count);
+ std::string msg(StringPrintf("Failed to allocate a %zd-byte %s (%lld total bytes free; largest possible contiguous allocation %zd bytes)",
+ byte_count,
+ PrettyDescriptor(c).c_str(),
+ total_bytes_free, max_contiguous_allocation));
+ Thread::Current()->ThrowOutOfMemoryError(msg.c_str());
return NULL;
}
@@ -491,11 +516,6 @@
return ptr;
}
- LOG(ERROR) << "Out of memory on a " << PrettySize(alloc_size) << " allocation";
-
- // TODO: tell the HeapSource to dump its state
- // TODO: dump stack traces for all threads
-
return NULL;
}
diff --git a/src/thread.cc b/src/thread.cc
index 1a39d99..fbc718c 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1424,12 +1424,6 @@
}
}
-void Thread::ThrowOutOfMemoryError(Class* c, size_t byte_count) {
- std::string msg(StringPrintf("Failed to allocate a %zd-byte %s", byte_count,
- PrettyDescriptor(c).c_str()));
- ThrowOutOfMemoryError(msg.c_str());
-}
-
void Thread::ThrowOutOfMemoryError(const char* msg) {
LOG(ERROR) << StringPrintf("Throwing OutOfMemoryError \"%s\"%s",
msg, (throwing_OutOfMemoryError_ ? " (recursive case)" : ""));
diff --git a/src/thread.h b/src/thread.h
index a100c03..2cb59d5 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -254,8 +254,8 @@
void ThrowNewExceptionV(const char* exception_class_descriptor, const char* fmt, va_list ap);
// OutOfMemoryError is special, because we need to pre-allocate an instance.
+ // Only the GC should call this.
void ThrowOutOfMemoryError(const char* msg);
- void ThrowOutOfMemoryError(Class* c, size_t byte_count);
Frame FindExceptionHandler(void* throw_pc, void** handler_pc);