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
// Verify for debugging.
void Verify() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes);
};
} // namespace allocator
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());
}
}
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;
}
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);
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>
}
#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
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,
#include "space.h"
+#include <iostream>
#include <valgrind.h>
#include <memcheck/memcheck.h>
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,
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,