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.
249 lines
9.7 KiB
249 lines
9.7 KiB
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
|
|
#define ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
|
|
|
|
#include "base/allocator.h"
|
|
#include "base/safe_map.h"
|
|
#include "base/tracking_safe_map.h"
|
|
#include "dlmalloc_space.h"
|
|
#include "space.h"
|
|
#include "thread-current-inl.h"
|
|
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
namespace art {
|
|
namespace gc {
|
|
namespace space {
|
|
|
|
class AllocationInfo;
|
|
|
|
enum class LargeObjectSpaceType {
|
|
kDisabled,
|
|
kMap,
|
|
kFreeList,
|
|
};
|
|
|
|
// Abstraction implemented by all large object spaces.
|
|
class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
|
|
public:
|
|
SpaceType GetType() const override {
|
|
return kSpaceTypeLargeObjectSpace;
|
|
}
|
|
void SwapBitmaps();
|
|
void CopyLiveToMarked();
|
|
virtual void Walk(DlMallocSpace::WalkCallback, void* arg) = 0;
|
|
virtual ~LargeObjectSpace() {}
|
|
|
|
uint64_t GetBytesAllocated() override {
|
|
MutexLock mu(Thread::Current(), lock_);
|
|
return num_bytes_allocated_;
|
|
}
|
|
uint64_t GetObjectsAllocated() override {
|
|
MutexLock mu(Thread::Current(), lock_);
|
|
return num_objects_allocated_;
|
|
}
|
|
uint64_t GetTotalBytesAllocated() const {
|
|
MutexLock mu(Thread::Current(), lock_);
|
|
return total_bytes_allocated_;
|
|
}
|
|
uint64_t GetTotalObjectsAllocated() const {
|
|
MutexLock mu(Thread::Current(), lock_);
|
|
return total_objects_allocated_;
|
|
}
|
|
size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) override;
|
|
// LargeObjectSpaces don't have thread local state.
|
|
size_t RevokeThreadLocalBuffers(art::Thread*) override {
|
|
return 0U;
|
|
}
|
|
size_t RevokeAllThreadLocalBuffers() override {
|
|
return 0U;
|
|
}
|
|
bool IsAllocSpace() const override {
|
|
return true;
|
|
}
|
|
AllocSpace* AsAllocSpace() override {
|
|
return this;
|
|
}
|
|
collector::ObjectBytePair Sweep(bool swap_bitmaps);
|
|
bool CanMoveObjects() const override {
|
|
return false;
|
|
}
|
|
// Current address at which the space begins, which may vary as the space is filled.
|
|
uint8_t* Begin() const {
|
|
return begin_;
|
|
}
|
|
// Current address at which the space ends, which may vary as the space is filled.
|
|
uint8_t* End() const {
|
|
return end_;
|
|
}
|
|
// Current size of space
|
|
size_t Size() const {
|
|
return End() - Begin();
|
|
}
|
|
// Return true if we contain the specified address.
|
|
bool Contains(const mirror::Object* obj) const override {
|
|
const uint8_t* byte_obj = reinterpret_cast<const uint8_t*>(obj);
|
|
return Begin() <= byte_obj && byte_obj < End();
|
|
}
|
|
bool LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) override
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
|
|
// Return true if the large object is a zygote large object. Potentially slow.
|
|
virtual bool IsZygoteLargeObject(Thread* self, mirror::Object* obj) const = 0;
|
|
// Called when we create the zygote space, mark all existing large objects as zygote large
|
|
// objects. Set mark-bit if called from PreZygoteFork() for ConcurrentCopying
|
|
// GC to avoid dirtying the first page.
|
|
virtual void SetAllLargeObjectsAsZygoteObjects(Thread* self, bool set_mark_bit) = 0;
|
|
|
|
virtual void ForEachMemMap(std::function<void(const MemMap&)> func) const = 0;
|
|
// GetRangeAtomic returns Begin() and End() atomically, that is, it never returns Begin() and
|
|
// End() from different allocations.
|
|
virtual std::pair<uint8_t*, uint8_t*> GetBeginEndAtomic() const = 0;
|
|
|
|
protected:
|
|
explicit LargeObjectSpace(const std::string& name, uint8_t* begin, uint8_t* end,
|
|
const char* lock_name);
|
|
static void SweepCallback(size_t num_ptrs, mirror::Object** ptrs, void* arg);
|
|
|
|
// Used to ensure mutual exclusion when the allocation spaces data structures,
|
|
// including the allocation counters below, are being modified.
|
|
mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
|
|
|
|
// Number of bytes which have been allocated into the space and not yet freed. The count is also
|
|
// included in the identically named field in Heap. Counts actual allocated (after rounding),
|
|
// not requested, sizes. TODO: It would be cheaper to just maintain total allocated and total
|
|
// free counts.
|
|
uint64_t num_bytes_allocated_ GUARDED_BY(lock_);
|
|
uint64_t num_objects_allocated_ GUARDED_BY(lock_);
|
|
|
|
// Totals for large objects ever allocated, including those that have since been deallocated.
|
|
// Never decremented.
|
|
uint64_t total_bytes_allocated_ GUARDED_BY(lock_);
|
|
uint64_t total_objects_allocated_ GUARDED_BY(lock_);
|
|
|
|
// Begin and end, may change as more large objects are allocated.
|
|
uint8_t* begin_;
|
|
uint8_t* end_;
|
|
|
|
friend class Space;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(LargeObjectSpace);
|
|
};
|
|
|
|
// A discontinuous large object space implemented by individual mmap/munmap calls.
|
|
class LargeObjectMapSpace : public LargeObjectSpace {
|
|
public:
|
|
// Creates a large object space. Allocations into the large object space use memory maps instead
|
|
// of malloc.
|
|
static LargeObjectMapSpace* Create(const std::string& name);
|
|
// Return the storage space required by obj.
|
|
size_t AllocationSize(mirror::Object* obj, size_t* usable_size) override REQUIRES(!lock_);
|
|
mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
|
|
size_t* usable_size, size_t* bytes_tl_bulk_allocated) override
|
|
REQUIRES(!lock_);
|
|
size_t Free(Thread* self, mirror::Object* ptr) override REQUIRES(!lock_);
|
|
void Walk(DlMallocSpace::WalkCallback, void* arg) override REQUIRES(!lock_);
|
|
// TODO: disabling thread safety analysis as this may be called when we already hold lock_.
|
|
bool Contains(const mirror::Object* obj) const override NO_THREAD_SAFETY_ANALYSIS;
|
|
void ForEachMemMap(std::function<void(const MemMap&)> func) const override REQUIRES(!lock_);
|
|
std::pair<uint8_t*, uint8_t*> GetBeginEndAtomic() const override REQUIRES(!lock_);
|
|
|
|
protected:
|
|
struct LargeObject {
|
|
MemMap mem_map;
|
|
bool is_zygote;
|
|
};
|
|
explicit LargeObjectMapSpace(const std::string& name);
|
|
virtual ~LargeObjectMapSpace() {}
|
|
|
|
bool IsZygoteLargeObject(Thread* self, mirror::Object* obj) const override REQUIRES(!lock_);
|
|
void SetAllLargeObjectsAsZygoteObjects(Thread* self, bool set_mark_bit) override
|
|
REQUIRES(!lock_)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
|
|
AllocationTrackingSafeMap<mirror::Object*, LargeObject, kAllocatorTagLOSMaps> large_objects_
|
|
GUARDED_BY(lock_);
|
|
};
|
|
|
|
// A continuous large object space with a free-list to handle holes.
|
|
class FreeListSpace final : public LargeObjectSpace {
|
|
public:
|
|
static constexpr size_t kAlignment = kPageSize;
|
|
|
|
virtual ~FreeListSpace();
|
|
static FreeListSpace* Create(const std::string& name, size_t capacity);
|
|
size_t AllocationSize(mirror::Object* obj, size_t* usable_size) override
|
|
REQUIRES(lock_);
|
|
mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated,
|
|
size_t* usable_size, size_t* bytes_tl_bulk_allocated)
|
|
override REQUIRES(!lock_);
|
|
size_t Free(Thread* self, mirror::Object* obj) override REQUIRES(!lock_);
|
|
void Walk(DlMallocSpace::WalkCallback callback, void* arg) override REQUIRES(!lock_);
|
|
void Dump(std::ostream& os) const override REQUIRES(!lock_);
|
|
void ForEachMemMap(std::function<void(const MemMap&)> func) const override REQUIRES(!lock_);
|
|
std::pair<uint8_t*, uint8_t*> GetBeginEndAtomic() const override REQUIRES(!lock_);
|
|
|
|
protected:
|
|
FreeListSpace(const std::string& name, MemMap&& mem_map, uint8_t* begin, uint8_t* end);
|
|
size_t GetSlotIndexForAddress(uintptr_t address) const {
|
|
DCHECK(Contains(reinterpret_cast<mirror::Object*>(address)));
|
|
return (address - reinterpret_cast<uintptr_t>(Begin())) / kAlignment;
|
|
}
|
|
size_t GetSlotIndexForAllocationInfo(const AllocationInfo* info) const;
|
|
AllocationInfo* GetAllocationInfoForAddress(uintptr_t address);
|
|
const AllocationInfo* GetAllocationInfoForAddress(uintptr_t address) const;
|
|
uintptr_t GetAllocationAddressForSlot(size_t slot) const {
|
|
return reinterpret_cast<uintptr_t>(Begin()) + slot * kAlignment;
|
|
}
|
|
uintptr_t GetAddressForAllocationInfo(const AllocationInfo* info) const {
|
|
return GetAllocationAddressForSlot(GetSlotIndexForAllocationInfo(info));
|
|
}
|
|
// Removes header from the free blocks set by finding the corresponding iterator and erasing it.
|
|
void RemoveFreePrev(AllocationInfo* info) REQUIRES(lock_);
|
|
bool IsZygoteLargeObject(Thread* self, mirror::Object* obj) const override;
|
|
void SetAllLargeObjectsAsZygoteObjects(Thread* self, bool set_mark_bit) override
|
|
REQUIRES(!lock_)
|
|
REQUIRES_SHARED(Locks::mutator_lock_);
|
|
|
|
class SortByPrevFree {
|
|
public:
|
|
bool operator()(const AllocationInfo* a, const AllocationInfo* b) const;
|
|
};
|
|
typedef std::set<AllocationInfo*, SortByPrevFree,
|
|
TrackingAllocator<AllocationInfo*, kAllocatorTagLOSFreeList>> FreeBlocks;
|
|
|
|
// There is not footer for any allocations at the end of the space, so we keep track of how much
|
|
// free space there is at the end manually.
|
|
MemMap mem_map_;
|
|
// Side table for allocation info, one per page.
|
|
MemMap allocation_info_map_;
|
|
AllocationInfo* allocation_info_;
|
|
|
|
// Free bytes at the end of the space.
|
|
size_t free_end_ GUARDED_BY(lock_);
|
|
FreeBlocks free_blocks_ GUARDED_BY(lock_);
|
|
};
|
|
|
|
} // namespace space
|
|
} // namespace gc
|
|
} // namespace art
|
|
|
|
#endif // ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
|