/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <stdio.h>
#include <cutils/trace.h>
#include "garbage_collector.h"
#include "base/logging.h"
#include "base/mutex-inl.h"
#include "gc/accounting/heap_bitmap.h"
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
#include "thread.h"
#include "thread_list.h"
namespace art {
namespace gc {
namespace collector {
GarbageCollector::GarbageCollector(Heap* heap, const std::string& name)
: heap_(heap),
name_(name),
verbose_(VLOG_IS_ON(heap)),
duration_ns_(0),
timings_(name_.c_str(), true, verbose_),
cumulative_timings_(name) {
ResetCumulativeStatistics();
}
bool GarbageCollector::HandleDirtyObjectsPhase() {
DCHECK(IsConcurrent());
return true;
}
void GarbageCollector::RegisterPause(uint64_t nano_length) {
pause_times_.push_back(nano_length);
}
void GarbageCollector::ResetCumulativeStatistics() {
cumulative_timings_.Reset();
total_time_ns_ = 0;
total_paused_time_ns_ = 0;
total_freed_objects_ = 0;
total_freed_bytes_ = 0;
}
void GarbageCollector::Run() {
ThreadList* thread_list = Runtime::Current()->GetThreadList();
uint64_t start_time = NanoTime();
pause_times_.clear();
duration_ns_ = 0;
InitializePhase();
if (!IsConcurrent()) {
// Pause is the entire length of the GC.
uint64_t pause_start = NanoTime();
ATRACE_BEGIN("Application threads suspended");
thread_list->SuspendAll();
MarkingPhase();
ReclaimPhase();
thread_list->ResumeAll();
ATRACE_END();
uint64_t pause_end = NanoTime();
pause_times_.push_back(pause_end - pause_start);
} else {
Thread* self = Thread::Current();
{
ReaderMutexLock mu(self, *Locks::mutator_lock_);
MarkingPhase();
}
bool done = false;
while (!done) {
uint64_t pause_start = NanoTime();
ATRACE_BEGIN("Suspending mutator threads");
thread_list->SuspendAll();
ATRACE_END();
ATRACE_BEGIN("All mutator threads suspended");
done = HandleDirtyObjectsPhase();
ATRACE_END();
uint64_t pause_end = NanoTime();
ATRACE_BEGIN("Resuming mutator threads");
thread_list->ResumeAll();
ATRACE_END();
pause_times_.push_back(pause_end - pause_start);
}
{
ReaderMutexLock mu(self, *Locks::mutator_lock_);
ReclaimPhase();
}
}
uint64_t end_time = NanoTime();
duration_ns_ = end_time - start_time;
FinishPhase();
}
void GarbageCollector::SwapBitmaps() {
// Swap the live and mark bitmaps for each alloc space. This is needed since sweep re-swaps
// these bitmaps. The bitmap swapping is an optimization so that we do not need to clear the live
// bits of dead objects in the live bitmap.
const GcType gc_type = GetGcType();
for (const auto& space : GetHeap()->GetContinuousSpaces()) {
// We never allocate into zygote spaces.
if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyAlwaysCollect ||
(gc_type == kGcTypeFull &&
space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect)) {
accounting::SpaceBitmap* live_bitmap = space->GetLiveBitmap();
accounting::SpaceBitmap* mark_bitmap = space->GetMarkBitmap();
if (live_bitmap != mark_bitmap) {
heap_->GetLiveBitmap()->ReplaceBitmap(live_bitmap, mark_bitmap);
heap_->GetMarkBitmap()->ReplaceBitmap(mark_bitmap, live_bitmap);
space->AsDlMallocSpace()->SwapBitmaps();
}
}
}
for (const auto& disc_space : GetHeap()->GetDiscontinuousSpaces()) {
space::LargeObjectSpace* space = down_cast<space::LargeObjectSpace*>(disc_space);
accounting::SpaceSetMap* live_set = space->GetLiveObjects();
accounting::SpaceSetMap* mark_set = space->GetMarkObjects();
heap_->GetLiveBitmap()->ReplaceObjectSet(live_set, mark_set);
heap_->GetMarkBitmap()->ReplaceObjectSet(mark_set, live_set);
down_cast<space::LargeObjectSpace*>(space)->SwapBitmaps();
}
}
} // namespace collector
} // namespace gc
} // namespace art