From 6bff7130878128c9836a21ae58d0cfdb0075b1b5 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Wed, 30 Jul 2014 14:59:56 -0700 Subject: [PATCH] Add support for bump pointer spaces to DdmSendHeapSegments. Added support for bump pointer spaces as well as differentiating between DlMallocSpaces and RosAllocSpaces. Added logic to reset the start of next chunk to prevent inbetween space regions counted as free. Fixed a debug build bug where we were doing an mprotect after creating a rosalloc space. In debug builds, this writes a magic value in the page. This was faulting since it was set to PROT_NONE. The fix moves the mprotect before the RosAlloc space creation. Bug: 16408851 (cherry picked from commit 36dab3607e77505ce139eacef1c62a1c4bc4affd) Change-Id: I5095feb01fa7e248178a2833da7f821f4fd52c89 --- runtime/debugger.cc | 53 +++++++++++++++++++++++++++++++++++++++++------------ runtime/gc/heap.cc | 2 +- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 0d906f1ea..7ee406b9f 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -3948,7 +3948,8 @@ class HeapChunkContext { HeapChunkContext(bool merge, bool native) : buf_(16384 - 16), type_(0), - merge_(merge) { + merge_(merge), + chunk_overhead_(0) { Reset(); if (native) { type_ = CHUNK_TYPE("NHSG"); @@ -3963,6 +3964,14 @@ class HeapChunkContext { } } + void SetChunkOverhead(size_t chunk_overhead) { + chunk_overhead_ = chunk_overhead; + } + + void ResetStartOfNextChunk() { + startOfNextMemoryChunk_ = nullptr; + } + void EnsureHeader(const void* chunk_ptr) { if (!needHeader_) { return; @@ -4007,7 +4016,7 @@ class HeapChunkContext { void Reset() { p_ = &buf_[0]; - startOfNextMemoryChunk_ = NULL; + ResetStartOfNextChunk(); totalAllocationUnits_ = 0; needHeader_ = true; pieceLenField_ = NULL; @@ -4034,6 +4043,8 @@ class HeapChunkContext { */ bool native = type_ == CHUNK_TYPE("NHSG"); + // TODO: I'm not sure using start of next chunk works well with multiple spaces. We shouldn't + // count gaps inbetween spaces as free memory. if (startOfNextMemoryChunk_ != NULL) { // Transmit any pending free memory. Native free memory of // over kMaxFreeLen could be because of the use of mmaps, so @@ -4060,11 +4071,8 @@ class HeapChunkContext { // OLD-TODO: if context.merge, see if this chunk is different from the last chunk. // If it's the same, we should combine them. uint8_t state = ExamineObject(obj, native); - // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an - // allocation then the first sizeof(size_t) may belong to it. - const size_t dlMallocOverhead = sizeof(size_t); - AppendChunk(state, start, used_bytes + dlMallocOverhead); - startOfNextMemoryChunk_ = reinterpret_cast(start) + used_bytes + dlMallocOverhead; + AppendChunk(state, start, used_bytes + chunk_overhead_); + startOfNextMemoryChunk_ = reinterpret_cast(start) + used_bytes + chunk_overhead_; } void AppendChunk(uint8_t state, void* ptr, size_t length) @@ -4153,10 +4161,18 @@ class HeapChunkContext { uint32_t type_; bool merge_; bool needHeader_; + size_t chunk_overhead_; DISALLOW_COPY_AND_ASSIGN(HeapChunkContext); }; +static void BumpPointerSpaceCallback(mirror::Object* obj, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) { + const size_t size = RoundUp(obj->SizeOf(), kObjectAlignment); + HeapChunkContext::HeapChunkCallback( + obj, reinterpret_cast(reinterpret_cast(obj) + size), size, arg); +} + void Dbg::DdmSendHeapSegments(bool native) { Dbg::HpsgWhen when; Dbg::HpsgWhat what; @@ -4197,14 +4213,27 @@ void Dbg::DdmSendHeapSegments(bool native) { #endif } else { gc::Heap* heap = Runtime::Current()->GetHeap(); - const std::vector& spaces = heap->GetContinuousSpaces(); - typedef std::vector::const_iterator It; - for (It cur = spaces.begin(), end = spaces.end(); cur != end; ++cur) { - if ((*cur)->IsMallocSpace()) { - (*cur)->AsMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); + for (const auto& space : heap->GetContinuousSpaces()) { + if (space->IsDlMallocSpace()) { + // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an + // allocation then the first sizeof(size_t) may belong to it. + context.SetChunkOverhead(sizeof(size_t)); + space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); + } else if (space->IsRosAllocSpace()) { + context.SetChunkOverhead(0); + space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); + } else if (space->IsBumpPointerSpace()) { + context.SetChunkOverhead(0); + ReaderMutexLock mu(self, *Locks::mutator_lock_); + WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_); + space->AsBumpPointerSpace()->Walk(BumpPointerSpaceCallback, &context); + } else { + UNIMPLEMENTED(WARNING) << "Not counting objects in space " << *space; } + context.ResetStartOfNextChunk(); } // Walk the large objects, these are not in the AllocSpace. + context.SetChunkOverhead(0); heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context); } diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index f7c708034..66cdd08db 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1624,12 +1624,12 @@ void Heap::TransitionCollector(CollectorType collector_type) { std::unique_ptr mem_map(temp_space_->ReleaseMemMap()); RemoveSpace(temp_space_); temp_space_ = nullptr; + mem_map->Protect(PROT_READ | PROT_WRITE); CreateMainMallocSpace(mem_map.get(), kDefaultInitialSize, mem_map->Size(), mem_map->Size()); mem_map.release(); // Compact to the main space from the bump pointer space, don't need to swap semispaces. AddSpace(main_space_); - main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE); Compact(main_space_, bump_pointer_space_, kGcCauseCollectorTransition); mem_map.reset(bump_pointer_space_->ReleaseMemMap()); RemoveSpace(bump_pointer_space_); -- 2.11.0