You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
524 lines
26 KiB
524 lines
26 KiB
/*
|
|
* Copyright (C) 2014 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.
|
|
*/
|
|
|
|
#ifndef ART_RUNTIME_GC_COLLECTOR_CONCURRENT_COPYING_H_
|
|
#define ART_RUNTIME_GC_COLLECTOR_CONCURRENT_COPYING_H_
|
|
|
|
#include "garbage_collector.h"
|
|
#include "gc/accounting/space_bitmap.h"
|
|
#include "immune_spaces.h"
|
|
#include "offsets.h"
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace art {
|
|
class Barrier;
|
|
class Closure;
|
|
class RootInfo;
|
|
|
|
namespace mirror {
|
|
template<class MirrorType> class CompressedReference;
|
|
template<class MirrorType> class HeapReference;
|
|
class Object;
|
|
} // namespace mirror
|
|
|
|
namespace gc {
|
|
|
|
namespace accounting {
|
|
template<typename T> class AtomicStack;
|
|
typedef AtomicStack<mirror::Object> ObjectStack;
|
|
template <size_t kAlignment> class SpaceBitmap;
|
|
typedef SpaceBitmap<kObjectAlignment> ContinuousSpaceBitmap;
|
|
class HeapBitmap;
|
|
class ReadBarrierTable;
|
|
} // namespace accounting
|
|
|
|
namespace space {
|
|
class RegionSpace;
|
|
} // namespace space
|
|
|
|
namespace collector {
|
|
|
|
class ConcurrentCopying : public GarbageCollector {
|
|
public:
|
|
// Enable the no-from-space-refs verification at the pause.
|
|
static constexpr bool kEnableNoFromSpaceRefsVerification = kIsDebugBuild;
|
|
// Enable the from-space bytes/objects check.
|
|
static constexpr bool kEnableFromSpaceAccountingCheck = kIsDebugBuild;
|
|
// Enable verbose mode.
|
|
static constexpr bool kVerboseMode = false;
|
|
// If kGrayDirtyImmuneObjects is true then we gray dirty objects in the GC pause to prevent dirty
|
|
// pages.
|
|
static constexpr bool kGrayDirtyImmuneObjects = true;
|
|
|
|
ConcurrentCopying(Heap* heap,
|
|
bool young_gen,
|
|
bool use_generational_cc,
|
|
const std::string& name_prefix = "",
|
|
bool measure_read_barrier_slow_path = false);
|
|
~ConcurrentCopying();
|
|
|
|
void RunPhases() override
|
|
REQUIRES(!immune_gray_stack_lock_,
|
|
!mark_stack_lock_,
|
|
!rb_slow_path_histogram_lock_,
|
|
!skipped_blocks_lock_);
|
|
void InitializePhase() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !immune_gray_stack_lock_);
|
|
void MarkingPhase() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void CopyingPhase() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void ReclaimPhase() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_);
|
|
void FinishPhase() REQUIRES(!mark_stack_lock_,
|
|
!rb_slow_path_histogram_lock_,
|
|
!skipped_blocks_lock_);
|
|
|
|
void CaptureRssAtPeak() REQUIRES(!mark_stack_lock_);
|
|
void BindBitmaps() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!Locks::heap_bitmap_lock_);
|
|
GcType GetGcType() const override {
|
|
return (use_generational_cc_ && young_gen_)
|
|
? kGcTypeSticky
|
|
: kGcTypePartial;
|
|
}
|
|
CollectorType GetCollectorType() const override {
|
|
return kCollectorTypeCC;
|
|
}
|
|
void RevokeAllThreadLocalBuffers() override;
|
|
// Creates inter-region ref bitmaps for region-space and non-moving-space.
|
|
// Gets called in Heap construction after the two spaces are created.
|
|
void CreateInterRegionRefBitmaps();
|
|
void SetRegionSpace(space::RegionSpace* region_space) {
|
|
DCHECK(region_space != nullptr);
|
|
region_space_ = region_space;
|
|
}
|
|
space::RegionSpace* RegionSpace() {
|
|
return region_space_;
|
|
}
|
|
// Assert the to-space invariant for a heap reference `ref` held in `obj` at offset `offset`.
|
|
void AssertToSpaceInvariant(mirror::Object* obj, MemberOffset offset, mirror::Object* ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
// Assert the to-space invariant for a GC root reference `ref`.
|
|
void AssertToSpaceInvariant(GcRootSource* gc_root_source, mirror::Object* ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
bool IsInToSpace(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_) {
|
|
DCHECK(ref != nullptr);
|
|
return IsMarked(ref) == ref;
|
|
}
|
|
// Mark object `from_ref`, copying it to the to-space if needed.
|
|
template<bool kGrayImmuneObject = true, bool kNoUnEvac = false, bool kFromGCThread = false>
|
|
ALWAYS_INLINE mirror::Object* Mark(Thread* const self,
|
|
mirror::Object* from_ref,
|
|
mirror::Object* holder = nullptr,
|
|
MemberOffset offset = MemberOffset(0))
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
ALWAYS_INLINE mirror::Object* MarkFromReadBarrier(mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
bool IsMarking() const {
|
|
return is_marking_;
|
|
}
|
|
// We may want to use read barrier entrypoints before is_marking_ is true since concurrent graying
|
|
// creates a small window where we might dispatch on these entrypoints.
|
|
bool IsUsingReadBarrierEntrypoints() const {
|
|
return is_using_read_barrier_entrypoints_;
|
|
}
|
|
bool IsActive() const {
|
|
return is_active_;
|
|
}
|
|
Barrier& GetBarrier() {
|
|
return *gc_barrier_;
|
|
}
|
|
bool IsWeakRefAccessEnabled() REQUIRES(Locks::thread_list_lock_) {
|
|
return weak_ref_access_enabled_;
|
|
}
|
|
void RevokeThreadLocalMarkStack(Thread* thread) REQUIRES(!mark_stack_lock_);
|
|
|
|
// Blindly return the forwarding pointer from the lockword, or null if there is none.
|
|
static mirror::Object* GetFwdPtrUnchecked(mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
|
|
// If marked, return the to-space object, otherwise null.
|
|
mirror::Object* IsMarked(mirror::Object* from_ref) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
|
|
void AssertNoThreadMarkStackMapping(Thread* thread) REQUIRES(!mark_stack_lock_);
|
|
|
|
private:
|
|
void PushOntoMarkStack(Thread* const self, mirror::Object* obj)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
// Returns a to-space copy of the from-space object from_ref, and atomically installs a
|
|
// forwarding pointer. Ensures that the forwarding reference is visible to other threads before
|
|
// the returned to-space pointer becomes visible to them.
|
|
mirror::Object* Copy(Thread* const self,
|
|
mirror::Object* from_ref,
|
|
mirror::Object* holder,
|
|
MemberOffset offset)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
// Scan the reference fields of object `to_ref`.
|
|
template <bool kNoUnEvac>
|
|
void Scan(mirror::Object* to_ref, size_t obj_size = 0) REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
// Scan the reference fields of object 'obj' in the dirty cards during
|
|
// card-table scan. In addition to visiting the references, it also sets the
|
|
// read-barrier state to gray for Reference-type objects to ensure that
|
|
// GetReferent() called on these objects calls the read-barrier on the referent.
|
|
template <bool kNoUnEvac>
|
|
void ScanDirtyObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
// Process a field.
|
|
template <bool kNoUnEvac>
|
|
void Process(mirror::Object* obj, MemberOffset offset)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_ , !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void VisitRoots(mirror::Object*** roots, size_t count, const RootInfo& info) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
template<bool kGrayImmuneObject>
|
|
void MarkRoot(Thread* const self, mirror::CompressedReference<mirror::Object>* root)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void VisitRoots(mirror::CompressedReference<mirror::Object>** roots,
|
|
size_t count,
|
|
const RootInfo& info) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void VerifyNoFromSpaceReferences() REQUIRES(Locks::mutator_lock_);
|
|
accounting::ObjectStack* GetAllocationStack();
|
|
accounting::ObjectStack* GetLiveStack();
|
|
void ProcessMarkStack() override REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
bool ProcessMarkStackOnce() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_);
|
|
void ProcessMarkStackRef(mirror::Object* to_ref) REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void GrayAllDirtyImmuneObjects()
|
|
REQUIRES(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void GrayAllNewlyDirtyImmuneObjects()
|
|
REQUIRES(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void VerifyGrayImmuneObjects()
|
|
REQUIRES(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void VerifyNoMissingCardMarks()
|
|
REQUIRES(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
template <typename Processor>
|
|
size_t ProcessThreadLocalMarkStacks(bool disable_weak_ref_access,
|
|
Closure* checkpoint_callback,
|
|
const Processor& processor)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_);
|
|
void RevokeThreadLocalMarkStacks(bool disable_weak_ref_access, Closure* checkpoint_callback)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void SwitchToSharedMarkStackMode() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
void SwitchToGcExclusiveMarkStackMode() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void DelayReferenceReferent(ObjPtr<mirror::Class> klass,
|
|
ObjPtr<mirror::Reference> reference) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void ProcessReferences(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
mirror::Object* MarkObject(mirror::Object* from_ref) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void MarkHeapReference(mirror::HeapReference<mirror::Object>* from_ref,
|
|
bool do_atomic_update) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
bool IsMarkedInUnevacFromSpace(mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
bool IsMarkedInNonMovingSpace(mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
bool IsNullOrMarkedHeapReference(mirror::HeapReference<mirror::Object>* field,
|
|
bool do_atomic_update) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void SweepSystemWeaks(Thread* self)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::heap_bitmap_lock_);
|
|
// Sweep unmarked objects to complete the garbage collection. Full GCs sweep
|
|
// all allocation spaces (except the region space). Sticky-bit GCs just sweep
|
|
// a subset of the heap.
|
|
void Sweep(bool swap_bitmaps)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_, !mark_stack_lock_);
|
|
// Sweep only pointers within an array.
|
|
void SweepArray(accounting::ObjectStack* allocation_stack_, bool swap_bitmaps)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_, !mark_stack_lock_);
|
|
void SweepLargeObjects(bool swap_bitmaps)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
|
|
void MarkZygoteLargeObjects()
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void FillWithFakeObject(Thread* const self, mirror::Object* fake_obj, size_t byte_size)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
mirror::Object* AllocateInSkippedBlock(Thread* const self, size_t alloc_size)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void CheckEmptyMarkStack() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_);
|
|
void IssueEmptyCheckpoint() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
bool IsOnAllocStack(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
// Return the forwarding pointer from the lockword. The argument must be in from space.
|
|
mirror::Object* GetFwdPtr(mirror::Object* from_ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void FlipThreadRoots() REQUIRES(!Locks::mutator_lock_);
|
|
void SwapStacks() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void RecordLiveStackFreezeSize(Thread* self);
|
|
void ComputeUnevacFromSpaceLiveRatio();
|
|
void LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset offset)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
// Dump information about reference `ref` and return it as a string.
|
|
// Use `ref_name` to name the reference in messages. Each message is prefixed with `indent`.
|
|
std::string DumpReferenceInfo(mirror::Object* ref, const char* ref_name, const char* indent = "")
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
// Dump information about heap reference `ref`, referenced from object `obj` at offset `offset`,
|
|
// and return it as a string.
|
|
std::string DumpHeapReference(mirror::Object* obj, MemberOffset offset, mirror::Object* ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
// Dump information about GC root `ref` and return it as a string.
|
|
std::string DumpGcRoot(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void ReenableWeakRefAccess(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void DisableMarking() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void IssueDisableMarkingCheckpoint() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void ExpandGcMarkStack() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
mirror::Object* MarkNonMoving(Thread* const self,
|
|
mirror::Object* from_ref,
|
|
mirror::Object* holder = nullptr,
|
|
MemberOffset offset = MemberOffset(0))
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_);
|
|
ALWAYS_INLINE mirror::Object* MarkUnevacFromSpaceRegion(Thread* const self,
|
|
mirror::Object* from_ref,
|
|
accounting::SpaceBitmap<kObjectAlignment>* bitmap)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_);
|
|
template<bool kGrayImmuneObject>
|
|
ALWAYS_INLINE mirror::Object* MarkImmuneSpace(Thread* const self,
|
|
mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!immune_gray_stack_lock_);
|
|
void ScanImmuneObject(mirror::Object* obj)
|
|
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_);
|
|
mirror::Object* MarkFromReadBarrierWithMeasurements(Thread* const self,
|
|
mirror::Object* from_ref)
|
|
REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_);
|
|
void DumpPerformanceInfo(std::ostream& os) override REQUIRES(!rb_slow_path_histogram_lock_);
|
|
// Set the read barrier mark entrypoints to non-null.
|
|
void ActivateReadBarrierEntrypoints();
|
|
|
|
void CaptureThreadRootsForMarking() REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void AddLiveBytesAndScanRef(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
bool TestMarkBitmapForRef(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
template <bool kAtomic = false>
|
|
bool TestAndSetMarkBitForRef(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void PushOntoLocalMarkStack(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_);
|
|
void ProcessMarkStackForMarkingAndComputeLiveBytes() REQUIRES_SHARED(Locks::mutator_lock_)
|
|
REQUIRES(!mark_stack_lock_);
|
|
|
|
void RemoveThreadMarkStackMapping(Thread* thread, accounting::ObjectStack* tl_mark_stack)
|
|
REQUIRES(mark_stack_lock_);
|
|
void AddThreadMarkStackMapping(Thread* thread, accounting::ObjectStack* tl_mark_stack)
|
|
REQUIRES(mark_stack_lock_);
|
|
void AssertEmptyThreadMarkStackMap() REQUIRES(mark_stack_lock_);
|
|
|
|
space::RegionSpace* region_space_; // The underlying region space.
|
|
std::unique_ptr<Barrier> gc_barrier_;
|
|
std::unique_ptr<accounting::ObjectStack> gc_mark_stack_;
|
|
|
|
// If true, enable generational collection when using the Concurrent Copying
|
|
// (CC) collector, i.e. use sticky-bit CC for minor collections and (full) CC
|
|
// for major collections. Generational CC collection is currently only
|
|
// compatible with Baker read barriers. Set in Heap constructor.
|
|
const bool use_generational_cc_;
|
|
|
|
// Generational "sticky", only trace through dirty objects in region space.
|
|
const bool young_gen_;
|
|
|
|
// If true, the GC thread is done scanning marked objects on dirty and aged
|
|
// card (see ConcurrentCopying::CopyingPhase).
|
|
Atomic<bool> done_scanning_;
|
|
|
|
// The read-barrier mark-bit stack. Stores object references whose
|
|
// mark bit has been set by ConcurrentCopying::MarkFromReadBarrier,
|
|
// so that this bit can be reset at the end of the collection in
|
|
// ConcurrentCopying::FinishPhase. The mark bit of an object can be
|
|
// used by mutator read barrier code to quickly test whether that
|
|
// object has been already marked.
|
|
std::unique_ptr<accounting::ObjectStack> rb_mark_bit_stack_;
|
|
// Thread-unsafe Boolean value hinting that `rb_mark_bit_stack_` is
|
|
// full. A thread-safe test of whether the read-barrier mark-bit
|
|
// stack is full is implemented by `rb_mark_bit_stack_->AtomicPushBack(ref)`
|
|
// (see use case in ConcurrentCopying::MarkFromReadBarrier).
|
|
bool rb_mark_bit_stack_full_;
|
|
|
|
// Guards access to pooled_mark_stacks_ and revoked_mark_stacks_ vectors.
|
|
// Also guards destruction and revocations of thread-local mark-stacks.
|
|
// Clearing thread-local mark-stack (by other threads or during destruction)
|
|
// should be guarded by it.
|
|
Mutex mark_stack_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
|
|
std::vector<accounting::ObjectStack*> revoked_mark_stacks_
|
|
GUARDED_BY(mark_stack_lock_);
|
|
static constexpr size_t kMarkStackSize = kPageSize;
|
|
static constexpr size_t kMarkStackPoolSize = 256;
|
|
std::vector<accounting::ObjectStack*> pooled_mark_stacks_
|
|
GUARDED_BY(mark_stack_lock_);
|
|
Thread* thread_running_gc_;
|
|
bool is_marking_; // True while marking is ongoing.
|
|
// True while we might dispatch on the read barrier entrypoints.
|
|
bool is_using_read_barrier_entrypoints_;
|
|
bool is_active_; // True while the collection is ongoing.
|
|
bool is_asserting_to_space_invariant_; // True while asserting the to-space invariant.
|
|
ImmuneSpaces immune_spaces_;
|
|
accounting::ContinuousSpaceBitmap* region_space_bitmap_;
|
|
// A cache of Heap::GetMarkBitmap().
|
|
accounting::HeapBitmap* heap_mark_bitmap_;
|
|
size_t live_stack_freeze_size_;
|
|
size_t from_space_num_objects_at_first_pause_; // Computed if kEnableFromSpaceAccountingCheck
|
|
size_t from_space_num_bytes_at_first_pause_; // Computed if kEnableFromSpaceAccountingCheck
|
|
Atomic<int> is_mark_stack_push_disallowed_;
|
|
enum MarkStackMode {
|
|
kMarkStackModeOff = 0, // Mark stack is off.
|
|
kMarkStackModeThreadLocal, // All threads except for the GC-running thread push refs onto
|
|
// thread-local mark stacks. The GC-running thread pushes onto and
|
|
// pops off the GC mark stack without a lock.
|
|
kMarkStackModeShared, // All threads share the GC mark stack with a lock.
|
|
kMarkStackModeGcExclusive // The GC-running thread pushes onto and pops from the GC mark stack
|
|
// without a lock. Other threads won't access the mark stack.
|
|
};
|
|
Atomic<MarkStackMode> mark_stack_mode_;
|
|
bool weak_ref_access_enabled_ GUARDED_BY(Locks::thread_list_lock_);
|
|
|
|
// How many objects and bytes we moved. The GC thread moves many more objects
|
|
// than mutators. Therefore, we separate the two to avoid CAS. Bytes_moved_ and
|
|
// bytes_moved_gc_thread_ are critical for GC triggering; the others are just informative.
|
|
Atomic<size_t> bytes_moved_; // Used by mutators
|
|
Atomic<size_t> objects_moved_; // Used by mutators
|
|
|
|
// copied_live_bytes_ratio_sum_ is read and written by CC per GC, in
|
|
// ReclaimPhase, and is read by DumpPerformanceInfo (potentially from another
|
|
// thread). However, at present, DumpPerformanceInfo is only called when the
|
|
// runtime shuts down, so no concurrent access. The same reasoning goes for
|
|
// gc_count_ and reclaimed_bytes_ratio_sum_
|
|
|
|
// The sum of of all copied live bytes ratio (to_bytes/from_bytes)
|
|
float copied_live_bytes_ratio_sum_;
|
|
// The number of GC counts, used to calculate the average above. (It doesn't
|
|
// include GC where from_bytes is zero, IOW, from-space is empty, which is
|
|
// possible for minor GC if all allocated objects are in non-moving
|
|
// space.)
|
|
size_t gc_count_;
|
|
// Bit is set if the corresponding object has inter-region references that
|
|
// were found during the marking phase of two-phase full-heap GC cycle.
|
|
accounting::ContinuousSpaceBitmap region_space_inter_region_bitmap_;
|
|
accounting::ContinuousSpaceBitmap non_moving_space_inter_region_bitmap_;
|
|
|
|
// reclaimed_bytes_ratio = reclaimed_bytes/num_allocated_bytes per GC cycle
|
|
float reclaimed_bytes_ratio_sum_;
|
|
|
|
// Used only by GC thread, so need not be atomic. Also, should be kept
|
|
// in a different cacheline than bytes/objects_moved_ (above) to avoid false
|
|
// cacheline sharing.
|
|
size_t bytes_moved_gc_thread_;
|
|
size_t objects_moved_gc_thread_;
|
|
uint64_t bytes_scanned_;
|
|
uint64_t cumulative_bytes_moved_;
|
|
uint64_t cumulative_objects_moved_;
|
|
|
|
// The skipped blocks are memory blocks/chucks that were copies of
|
|
// objects that were unused due to lost races (cas failures) at
|
|
// object copy/forward pointer install. They may be reused.
|
|
// Skipped blocks are always in region space. Their size is included directly
|
|
// in num_bytes_allocated_, i.e. they are treated as allocated, but may be directly
|
|
// used without going through a GC cycle like other objects. They are reused only
|
|
// if we run out of region space. TODO: Revisit this design.
|
|
Mutex skipped_blocks_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
|
|
std::multimap<size_t, uint8_t*> skipped_blocks_map_ GUARDED_BY(skipped_blocks_lock_);
|
|
Atomic<size_t> to_space_bytes_skipped_;
|
|
Atomic<size_t> to_space_objects_skipped_;
|
|
|
|
// If measure_read_barrier_slow_path_ is true, we count how long is spent in MarkFromReadBarrier
|
|
// and also log.
|
|
bool measure_read_barrier_slow_path_;
|
|
// mark_from_read_barrier_measurements_ is true if systrace is enabled or
|
|
// measure_read_barrier_time_ is true.
|
|
bool mark_from_read_barrier_measurements_;
|
|
Atomic<uint64_t> rb_slow_path_ns_;
|
|
Atomic<uint64_t> rb_slow_path_count_;
|
|
Atomic<uint64_t> rb_slow_path_count_gc_;
|
|
mutable Mutex rb_slow_path_histogram_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
|
|
Histogram<uint64_t> rb_slow_path_time_histogram_ GUARDED_BY(rb_slow_path_histogram_lock_);
|
|
uint64_t rb_slow_path_count_total_ GUARDED_BY(rb_slow_path_histogram_lock_);
|
|
uint64_t rb_slow_path_count_gc_total_ GUARDED_BY(rb_slow_path_histogram_lock_);
|
|
|
|
accounting::ReadBarrierTable* rb_table_;
|
|
bool force_evacuate_all_; // True if all regions are evacuated.
|
|
Atomic<bool> updated_all_immune_objects_;
|
|
bool gc_grays_immune_objects_;
|
|
Mutex immune_gray_stack_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
|
|
std::vector<mirror::Object*> immune_gray_stack_ GUARDED_BY(immune_gray_stack_lock_);
|
|
|
|
// Class of java.lang.Object. Filled in from WellKnownClasses in FlipCallback. Must
|
|
// be filled in before flipping thread roots so that FillWithFakeObject can run. Not
|
|
// ObjPtr since the GC may transition to suspended and runnable between phases.
|
|
mirror::Class* java_lang_Object_;
|
|
|
|
// Sweep array free buffer, used to sweep the spaces based on an array more
|
|
// efficiently, by recording dead objects to be freed in batches (see
|
|
// ConcurrentCopying::SweepArray).
|
|
MemMap sweep_array_free_buffer_mem_map_;
|
|
|
|
// Use signed because after_gc may be larger than before_gc.
|
|
int64_t num_bytes_allocated_before_gc_;
|
|
|
|
class ActivateReadBarrierEntrypointsCallback;
|
|
class ActivateReadBarrierEntrypointsCheckpoint;
|
|
class AssertToSpaceInvariantFieldVisitor;
|
|
class AssertToSpaceInvariantRefsVisitor;
|
|
class ClearBlackPtrsVisitor;
|
|
class ComputeUnevacFromSpaceLiveRatioVisitor;
|
|
class DisableMarkingCallback;
|
|
class DisableMarkingCheckpoint;
|
|
class DisableWeakRefAccessCallback;
|
|
class FlipCallback;
|
|
template <bool kConcurrent> class GrayImmuneObjectVisitor;
|
|
class ImmuneSpaceScanObjVisitor;
|
|
class LostCopyVisitor;
|
|
template <bool kNoUnEvac> class RefFieldsVisitor;
|
|
class RevokeThreadLocalMarkStackCheckpoint;
|
|
class ScopedGcGraysImmuneObjects;
|
|
class ThreadFlipVisitor;
|
|
class VerifyGrayImmuneObjectsVisitor;
|
|
class VerifyNoFromSpaceRefsFieldVisitor;
|
|
class VerifyNoFromSpaceRefsVisitor;
|
|
class VerifyNoMissingCardMarkVisitor;
|
|
class ImmuneSpaceCaptureRefsVisitor;
|
|
template <bool kAtomicTestAndSet = false> class CaptureRootsForMarkingVisitor;
|
|
class CaptureThreadRootsForMarkingAndCheckpoint;
|
|
template <bool kHandleInterRegionRefs> class ComputeLiveBytesAndMarkRefFieldsVisitor;
|
|
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ConcurrentCopying);
|
|
};
|
|
|
|
} // namespace collector
|
|
} // namespace gc
|
|
} // namespace art
|
|
|
|
#endif // ART_RUNTIME_GC_COLLECTOR_CONCURRENT_COPYING_H_
|