Change FreeMemory and TotalMemory behavior.
TotalMemory is now equal to the footprint limit (around when the
next GC will occur).
FreeMemory is now equal to TotalMemory() - bytes_allocated_.
Also added more memory dumping info to DumpGcPerformanceInfo.
Bug: 16520008
Bug: 15819878
Change-Id: Ifa59a2f2136dd0704097411ee183925e6c387fae
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 6d8190e..1ea514b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -787,10 +787,15 @@
os << "Mean GC object throughput: "
<< (GetObjectsFreedEver() / total_seconds) << " objects/s\n";
}
- size_t total_objects_allocated = GetObjectsAllocatedEver();
+ uint64_t total_objects_allocated = GetObjectsAllocatedEver();
os << "Total number of allocations: " << total_objects_allocated << "\n";
- size_t total_bytes_allocated = GetBytesAllocatedEver();
+ uint64_t total_bytes_allocated = GetBytesAllocatedEver();
os << "Total bytes allocated " << PrettySize(total_bytes_allocated) << "\n";
+ os << "Free memory" << PrettySize(GetFreeMemoryUntilGC()) << "\n";
+ os << "Free memory until GC " << PrettySize(GetFreeMemoryUntilGC()) << "\n";
+ os << "Free memory until OOME " << PrettySize(GetFreeMemoryUntilOOME()) << "\n";
+ os << "Total memory" << PrettySize(GetTotalMemory()) << "\n";
+ os << "Max memory" << PrettySize(GetMaxMemory()) << "\n";
if (kMeasureAllocationTime) {
os << "Total time spent allocating: " << PrettyDuration(allocation_time) << "\n";
os << "Mean allocation time: " << PrettyDuration(allocation_time / total_objects_allocated)
@@ -864,7 +869,7 @@
std::ostringstream oss;
size_t total_bytes_free = GetFreeMemory();
oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free
- << " free bytes";
+ << " free bytes and " << PrettySize(GetFreeMemoryUntilOOME()) << " until OOM";
// If the allocation failed due to fragmentation, print out the largest continuous allocation.
if (total_bytes_free >= byte_count) {
space::AllocSpace* space = nullptr;
@@ -1313,11 +1318,11 @@
return total;
}
-size_t Heap::GetObjectsAllocatedEver() const {
+uint64_t Heap::GetObjectsAllocatedEver() const {
return GetObjectsFreedEver() + GetObjectsAllocated();
}
-size_t Heap::GetBytesAllocatedEver() const {
+uint64_t Heap::GetBytesAllocatedEver() const {
return GetBytesFreedEver() + GetBytesAllocated();
}
@@ -2847,7 +2852,7 @@
remaining_bytes = kMinConcurrentRemainingBytes;
}
DCHECK_LE(remaining_bytes, max_allowed_footprint_);
- DCHECK_LE(max_allowed_footprint_, growth_limit_);
+ DCHECK_LE(max_allowed_footprint_, GetMaxMemory());
// Start a concurrent GC when we get close to the estimated remaining bytes. When the
// allocation rate is very high, remaining_bytes could tell us that we should start a GC
// right away.
@@ -3077,19 +3082,7 @@
}
size_t Heap::GetTotalMemory() const {
- size_t ret = 0;
- for (const auto& space : continuous_spaces_) {
- // Currently don't include the image space.
- if (!space->IsImageSpace()) {
- ret += space->Size();
- }
- }
- for (const auto& space : discontinuous_spaces_) {
- if (space->IsLargeObjectSpace()) {
- ret += space->AsLargeObjectSpace()->GetBytesAllocated();
- }
- }
- return ret;
+ return std::max(max_allowed_footprint_, GetBytesAllocated());
}
void Heap::AddModUnionTable(accounting::ModUnionTable* mod_union_table) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1851662..d5b49d8 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -401,18 +401,18 @@
size_t GetObjectsAllocated() const LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
// Returns the total number of objects allocated since the heap was created.
- size_t GetObjectsAllocatedEver() const;
+ uint64_t GetObjectsAllocatedEver() const;
// Returns the total number of bytes allocated since the heap was created.
- size_t GetBytesAllocatedEver() const;
+ uint64_t GetBytesAllocatedEver() const;
// Returns the total number of objects freed since the heap was created.
- size_t GetObjectsFreedEver() const {
+ uint64_t GetObjectsFreedEver() const {
return total_objects_freed_ever_;
}
// Returns the total number of bytes freed since the heap was created.
- size_t GetBytesFreedEver() const {
+ uint64_t GetBytesFreedEver() const {
return total_bytes_freed_ever_;
}
@@ -421,19 +421,32 @@
// were specified. Android apps start with a growth limit (small heap size) which is
// cleared/extended for large apps.
size_t GetMaxMemory() const {
- return growth_limit_;
+ // There is some race conditions in the allocation code that can cause bytes allocated to
+ // become larger than growth_limit_ in rare cases.
+ return std::max(GetBytesAllocated(), growth_limit_);
}
- // Implements java.lang.Runtime.totalMemory, returning the amount of memory consumed by an
- // application.
+ // Implements java.lang.Runtime.totalMemory, returning approximate amount of memory currently
+ // consumed by an application.
size_t GetTotalMemory() const;
- // Implements java.lang.Runtime.freeMemory.
+ // Returns approximately how much free memory we have until the next GC happens.
+ size_t GetFreeMemoryUntilGC() const {
+ return max_allowed_footprint_ - GetBytesAllocated();
+ }
+
+ // Returns approximately how much free memory we have until the next OOME happens.
+ size_t GetFreeMemoryUntilOOME() const {
+ return growth_limit_ - GetBytesAllocated();
+ }
+
+ // Returns how much free memory we have until we need to grow the heap to perform an allocation.
+ // Similar to GetFreeMemoryUntilGC. Implements java.lang.Runtime.freeMemory.
size_t GetFreeMemory() const {
size_t byte_allocated = num_bytes_allocated_.LoadSequentiallyConsistent();
- // Make sure we don't get a negative number since the max allowed footprint is only updated
- // after the GC. But we can still allocate even if bytes_allocated > max_allowed_footprint_.
- return std::max(max_allowed_footprint_, byte_allocated) - byte_allocated;
+ size_t total_memory = GetTotalMemory();
+ // Make sure we don't get a negative number.
+ return total_memory - std::min(total_memory, byte_allocated);
}
// get the space that corresponds to an object's address. Current implementation searches all
@@ -885,10 +898,10 @@
size_t concurrent_start_bytes_;
// Since the heap was created, how many bytes have been freed.
- size_t total_bytes_freed_ever_;
+ uint64_t total_bytes_freed_ever_;
// Since the heap was created, how many objects have been freed.
- size_t total_objects_freed_ever_;
+ uint64_t total_objects_freed_ever_;
// Number of bytes allocated. Adjusted after each allocation and free.
Atomic<size_t> num_bytes_allocated_;