• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
18 #define ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
19 
20 #include "gc/accounting/gc_allocator.h"
21 #include "dlmalloc_space.h"
22 #include "safe_map.h"
23 #include "space.h"
24 
25 #include <set>
26 #include <vector>
27 
28 namespace art {
29 namespace gc {
30 namespace space {
31 
32 // Abstraction implemented by all large object spaces.
33 class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
34  public:
GetType()35   virtual SpaceType GetType() const {
36     return kSpaceTypeLargeObjectSpace;
37   }
38 
39   virtual void SwapBitmaps();
40   virtual void CopyLiveToMarked();
41   virtual void Walk(DlMallocSpace::WalkCallback, void* arg) = 0;
~LargeObjectSpace()42   virtual ~LargeObjectSpace() {}
43 
GetBytesAllocated()44   uint64_t GetBytesAllocated() const {
45     return num_bytes_allocated_;
46   }
47 
GetObjectsAllocated()48   uint64_t GetObjectsAllocated() const {
49     return num_objects_allocated_;
50   }
51 
GetTotalBytesAllocated()52   uint64_t GetTotalBytesAllocated() const {
53     return total_bytes_allocated_;
54   }
55 
GetTotalObjectsAllocated()56   uint64_t GetTotalObjectsAllocated() const {
57     return total_objects_allocated_;
58   }
59 
60   size_t FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs);
61 
62  protected:
63   explicit LargeObjectSpace(const std::string& name);
64 
65   // Approximate number of bytes which have been allocated into the space.
66   size_t num_bytes_allocated_;
67   size_t num_objects_allocated_;
68   size_t total_bytes_allocated_;
69   size_t total_objects_allocated_;
70 
71   friend class Space;
72 
73  private:
74   DISALLOW_COPY_AND_ASSIGN(LargeObjectSpace);
75 };
76 
77 // A discontinuous large object space implemented by individual mmap/munmap calls.
78 class LargeObjectMapSpace : public LargeObjectSpace {
79  public:
80   // Creates a large object space. Allocations into the large object space use memory maps instead
81   // of malloc.
82   static LargeObjectMapSpace* Create(const std::string& name);
83 
84   // Return the storage space required by obj.
85   size_t AllocationSize(const mirror::Object* obj);
86   mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated);
87   size_t Free(Thread* self, mirror::Object* ptr);
88   void Walk(DlMallocSpace::WalkCallback, void* arg) LOCKS_EXCLUDED(lock_);
89   // TODO: disabling thread safety analysis as this may be called when we already hold lock_.
90   bool Contains(const mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS;
91 
92  private:
93   explicit LargeObjectMapSpace(const std::string& name);
~LargeObjectMapSpace()94   virtual ~LargeObjectMapSpace() {}
95 
96   // Used to ensure mutual exclusion when the allocation spaces data structures are being modified.
97   mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
98   std::vector<mirror::Object*,
99       accounting::GCAllocator<mirror::Object*> > large_objects_ GUARDED_BY(lock_);
100   typedef SafeMap<mirror::Object*, MemMap*, std::less<mirror::Object*>,
101       accounting::GCAllocator<std::pair<const mirror::Object*, MemMap*> > > MemMaps;
102   MemMaps mem_maps_ GUARDED_BY(lock_);
103 };
104 
105 // A continuous large object space with a free-list to handle holes.
106 class FreeListSpace : public LargeObjectSpace {
107  public:
108   virtual ~FreeListSpace();
109   static FreeListSpace* Create(const std::string& name, byte* requested_begin, size_t capacity);
110 
111   size_t AllocationSize(const mirror::Object* obj) EXCLUSIVE_LOCKS_REQUIRED(lock_);
112   mirror::Object* Alloc(Thread* self, size_t num_bytes, size_t* bytes_allocated);
113   size_t Free(Thread* self, mirror::Object* obj);
114   bool Contains(const mirror::Object* obj) const;
115   void Walk(DlMallocSpace::WalkCallback callback, void* arg) LOCKS_EXCLUDED(lock_);
116 
117   // Address at which the space begins.
Begin()118   byte* Begin() const {
119     return begin_;
120   }
121 
122   // Address at which the space ends, which may vary as the space is filled.
End()123   byte* End() const {
124     return end_;
125   }
126 
127   // Current size of space
Size()128   size_t Size() const {
129     return End() - Begin();
130   }
131 
132   void Dump(std::ostream& os) const;
133 
134  private:
135   static const size_t kAlignment = kPageSize;
136 
137   class AllocationHeader {
138    public:
139     // Returns the allocation size, includes the header.
AllocationSize()140     size_t AllocationSize() const {
141       return alloc_size_;
142     }
143 
144     // Updates the allocation size in the header, the allocation size includes the header itself.
SetAllocationSize(size_t size)145     void SetAllocationSize(size_t size) {
146       DCHECK(IsAligned<kPageSize>(size));
147       alloc_size_ = size;
148     }
149 
IsFree()150     bool IsFree() const {
151       return AllocationSize() == 0;
152     }
153 
154     // Returns the previous free allocation header by using the prev_free_ member to figure out
155     // where it is. If prev free is 0 then we just return ourself.
GetPrevFreeAllocationHeader()156     AllocationHeader* GetPrevFreeAllocationHeader() {
157       return reinterpret_cast<AllocationHeader*>(reinterpret_cast<uintptr_t>(this) - prev_free_);
158     }
159 
160     // Returns the address of the object associated with this allocation header.
GetObjectAddress()161     mirror::Object* GetObjectAddress() {
162       return reinterpret_cast<mirror::Object*>(reinterpret_cast<uintptr_t>(this) + sizeof(*this));
163     }
164 
165     // Returns the next allocation header after the object associated with this allocation header.
GetNextAllocationHeader()166     AllocationHeader* GetNextAllocationHeader() {
167       DCHECK_NE(alloc_size_, 0U);
168       return reinterpret_cast<AllocationHeader*>(reinterpret_cast<uintptr_t>(this) + alloc_size_);
169     }
170 
171     // Returns how many free bytes there is before the block.
GetPrevFree()172     size_t GetPrevFree() const {
173       return prev_free_;
174     }
175 
176     // Update the size of the free block prior to the allocation.
SetPrevFree(size_t prev_free)177     void SetPrevFree(size_t prev_free) {
178       DCHECK(IsAligned<kPageSize>(prev_free));
179       prev_free_ = prev_free;
180     }
181 
182     // Finds and returns the next non free allocation header after ourself.
183     // TODO: Optimize, currently O(n) for n free following pages.
184     AllocationHeader* GetNextNonFree();
185 
186     // Used to implement best fit object allocation. Each allocation has an AllocationHeader which
187     // contains the size of the previous free block preceding it. Implemented in such a way that we
188     // can also find the iterator for any allocation header pointer.
189     class SortByPrevFree {
190      public:
operator()191       bool operator()(const AllocationHeader* a, const AllocationHeader* b) const {
192         if (a->GetPrevFree() < b->GetPrevFree()) return true;
193         if (a->GetPrevFree() > b->GetPrevFree()) return false;
194         if (a->AllocationSize() < b->AllocationSize()) return true;
195         if (a->AllocationSize() > b->AllocationSize()) return false;
196         return reinterpret_cast<uintptr_t>(a) < reinterpret_cast<uintptr_t>(b);
197       }
198     };
199 
200    private:
201     // Contains the size of the previous free block, if 0 then the memory preceding us is an
202     // allocation.
203     size_t prev_free_;
204 
205     // Allocation size of this object, 0 means that the allocation header is free memory.
206     size_t alloc_size_;
207 
208     friend class FreeListSpace;
209   };
210 
211   FreeListSpace(const std::string& name, MemMap* mem_map, byte* begin, byte* end);
212 
213   // Removes header from the free blocks set by finding the corresponding iterator and erasing it.
214   void RemoveFreePrev(AllocationHeader* header) EXCLUSIVE_LOCKS_REQUIRED(lock_);
215 
216   // Finds the allocation header corresponding to obj.
217   AllocationHeader* GetAllocationHeader(const mirror::Object* obj);
218 
219   typedef std::set<AllocationHeader*, AllocationHeader::SortByPrevFree,
220                    accounting::GCAllocator<AllocationHeader*> > FreeBlocks;
221 
222   byte* const begin_;
223   byte* const end_;
224 
225   // There is not footer for any allocations at the end of the space, so we keep track of how much
226   // free space there is at the end manually.
227   UniquePtr<MemMap> mem_map_;
228   Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
229   size_t free_end_ GUARDED_BY(lock_);
230   FreeBlocks free_blocks_ GUARDED_BY(lock_);
231 };
232 
233 }  // namespace space
234 }  // namespace gc
235 }  // namespace art
236 
237 #endif  // ART_RUNTIME_GC_SPACE_LARGE_OBJECT_SPACE_H_
238