xref: /aosp_15_r20/art/runtime/gc/space/dlmalloc_space.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "dlmalloc_space-inl.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <sys/mman.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"  // For VLOG.
22*795d594fSAndroid Build Coastguard Worker #include "base/time_utils.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
24*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/card_table.h"
25*795d594fSAndroid Build Coastguard Worker #include "gc/accounting/space_bitmap-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "gc/heap.h"
27*795d594fSAndroid Build Coastguard Worker #include "jit/jit.h"
28*795d594fSAndroid Build Coastguard Worker #include "jit/jit_code_cache.h"
29*795d594fSAndroid Build Coastguard Worker #include "memory_tool_malloc_space-inl.h"
30*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
33*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
34*795d594fSAndroid Build Coastguard Worker #include "thread.h"
35*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
38*795d594fSAndroid Build Coastguard Worker namespace gc {
39*795d594fSAndroid Build Coastguard Worker namespace space {
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker static constexpr bool kPrefetchDuringDlMallocFreeList = true;
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker // Callback for mspace_inspect_all that will madvise(2) unused pages back to
44*795d594fSAndroid Build Coastguard Worker // the kernel.
DlmallocMadviseCallback(void * start,void * end,size_t used_bytes,void * arg)45*795d594fSAndroid Build Coastguard Worker void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
46*795d594fSAndroid Build Coastguard Worker   // Is this chunk in use?
47*795d594fSAndroid Build Coastguard Worker   if (used_bytes != 0) {
48*795d594fSAndroid Build Coastguard Worker     return;
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker   // Do we have any whole pages to give back?
51*795d594fSAndroid Build Coastguard Worker   start = reinterpret_cast<void*>(art::RoundUp(reinterpret_cast<uintptr_t>(start), art::gPageSize));
52*795d594fSAndroid Build Coastguard Worker   end = reinterpret_cast<void*>(art::RoundDown(reinterpret_cast<uintptr_t>(end), art::gPageSize));
53*795d594fSAndroid Build Coastguard Worker   if (end > start) {
54*795d594fSAndroid Build Coastguard Worker     size_t length = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start);
55*795d594fSAndroid Build Coastguard Worker     int rc = madvise(start, length, MADV_DONTNEED);
56*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(rc != 0)) {
57*795d594fSAndroid Build Coastguard Worker       errno = rc;
58*795d594fSAndroid Build Coastguard Worker       PLOG(FATAL) << "madvise failed during heap trimming";
59*795d594fSAndroid Build Coastguard Worker     }
60*795d594fSAndroid Build Coastguard Worker     size_t* reclaimed = reinterpret_cast<size_t*>(arg);
61*795d594fSAndroid Build Coastguard Worker     *reclaimed += length;
62*795d594fSAndroid Build Coastguard Worker   }
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker // Callback for mspace_inspect_all that will count the number of bytes
66*795d594fSAndroid Build Coastguard Worker // allocated.
DlmallocBytesAllocatedCallback(void * start,void * end,size_t used_bytes,void * arg)67*795d594fSAndroid Build Coastguard Worker void DlmallocBytesAllocatedCallback([[maybe_unused]] void* start,
68*795d594fSAndroid Build Coastguard Worker                                     [[maybe_unused]] void* end,
69*795d594fSAndroid Build Coastguard Worker                                     size_t used_bytes,
70*795d594fSAndroid Build Coastguard Worker                                     void* arg) {
71*795d594fSAndroid Build Coastguard Worker   if (used_bytes == 0) {
72*795d594fSAndroid Build Coastguard Worker     return;
73*795d594fSAndroid Build Coastguard Worker   }
74*795d594fSAndroid Build Coastguard Worker   size_t* bytes_allocated = reinterpret_cast<size_t*>(arg);
75*795d594fSAndroid Build Coastguard Worker   *bytes_allocated += used_bytes + sizeof(size_t);
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker // Callback for mspace_inspect_all that will count the number of objects
79*795d594fSAndroid Build Coastguard Worker // allocated.
DlmallocObjectsAllocatedCallback(void * start,void * end,size_t used_bytes,void * arg)80*795d594fSAndroid Build Coastguard Worker void DlmallocObjectsAllocatedCallback([[maybe_unused]] void* start,
81*795d594fSAndroid Build Coastguard Worker                                       [[maybe_unused]] void* end,
82*795d594fSAndroid Build Coastguard Worker                                       size_t used_bytes,
83*795d594fSAndroid Build Coastguard Worker                                       void* arg) {
84*795d594fSAndroid Build Coastguard Worker   if (used_bytes == 0) {
85*795d594fSAndroid Build Coastguard Worker     return;
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker   size_t* objects_allocated = reinterpret_cast<size_t*>(arg);
88*795d594fSAndroid Build Coastguard Worker   ++(*objects_allocated);
89*795d594fSAndroid Build Coastguard Worker }
90*795d594fSAndroid Build Coastguard Worker 
DlMallocSpace(MemMap && mem_map,size_t initial_size,const std::string & name,void * mspace,uint8_t * begin,uint8_t * end,uint8_t * limit,size_t growth_limit,bool can_move_objects,size_t starting_size)91*795d594fSAndroid Build Coastguard Worker DlMallocSpace::DlMallocSpace(MemMap&& mem_map,
92*795d594fSAndroid Build Coastguard Worker                              size_t initial_size,
93*795d594fSAndroid Build Coastguard Worker                              const std::string& name,
94*795d594fSAndroid Build Coastguard Worker                              void* mspace,
95*795d594fSAndroid Build Coastguard Worker                              uint8_t* begin,
96*795d594fSAndroid Build Coastguard Worker                              uint8_t* end,
97*795d594fSAndroid Build Coastguard Worker                              uint8_t* limit,
98*795d594fSAndroid Build Coastguard Worker                              size_t growth_limit,
99*795d594fSAndroid Build Coastguard Worker                              bool can_move_objects,
100*795d594fSAndroid Build Coastguard Worker                              size_t starting_size)
101*795d594fSAndroid Build Coastguard Worker     : MallocSpace(name,
102*795d594fSAndroid Build Coastguard Worker                   std::move(mem_map),
103*795d594fSAndroid Build Coastguard Worker                   begin,
104*795d594fSAndroid Build Coastguard Worker                   end,
105*795d594fSAndroid Build Coastguard Worker                   limit,
106*795d594fSAndroid Build Coastguard Worker                   growth_limit,
107*795d594fSAndroid Build Coastguard Worker                   /* create_bitmaps= */ true,
108*795d594fSAndroid Build Coastguard Worker                   can_move_objects,
109*795d594fSAndroid Build Coastguard Worker                   starting_size, initial_size),
110*795d594fSAndroid Build Coastguard Worker       mspace_(mspace) {
111*795d594fSAndroid Build Coastguard Worker   CHECK(mspace != nullptr);
112*795d594fSAndroid Build Coastguard Worker }
113*795d594fSAndroid Build Coastguard Worker 
CreateFromMemMap(MemMap && mem_map,const std::string & name,size_t starting_size,size_t initial_size,size_t growth_limit,size_t capacity,bool can_move_objects)114*795d594fSAndroid Build Coastguard Worker DlMallocSpace* DlMallocSpace::CreateFromMemMap(MemMap&& mem_map,
115*795d594fSAndroid Build Coastguard Worker                                                const std::string& name,
116*795d594fSAndroid Build Coastguard Worker                                                size_t starting_size,
117*795d594fSAndroid Build Coastguard Worker                                                size_t initial_size,
118*795d594fSAndroid Build Coastguard Worker                                                size_t growth_limit,
119*795d594fSAndroid Build Coastguard Worker                                                size_t capacity,
120*795d594fSAndroid Build Coastguard Worker                                                bool can_move_objects) {
121*795d594fSAndroid Build Coastguard Worker   DCHECK(mem_map.IsValid());
122*795d594fSAndroid Build Coastguard Worker   void* mspace = CreateMspace(mem_map.Begin(), starting_size, initial_size);
123*795d594fSAndroid Build Coastguard Worker   if (mspace == nullptr) {
124*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to initialize mspace for alloc space (" << name << ")";
125*795d594fSAndroid Build Coastguard Worker     return nullptr;
126*795d594fSAndroid Build Coastguard Worker   }
127*795d594fSAndroid Build Coastguard Worker 
128*795d594fSAndroid Build Coastguard Worker   // Protect memory beyond the starting size. morecore will add r/w permissions when necessory
129*795d594fSAndroid Build Coastguard Worker   uint8_t* end = mem_map.Begin() + starting_size;
130*795d594fSAndroid Build Coastguard Worker   if (capacity - starting_size > 0) {
131*795d594fSAndroid Build Coastguard Worker     CheckedCall(mprotect, name.c_str(), end, capacity - starting_size, PROT_NONE);
132*795d594fSAndroid Build Coastguard Worker   }
133*795d594fSAndroid Build Coastguard Worker 
134*795d594fSAndroid Build Coastguard Worker   // Everything is set so record in immutable structure and leave
135*795d594fSAndroid Build Coastguard Worker   uint8_t* begin = mem_map.Begin();
136*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current()->IsRunningOnMemoryTool()) {
137*795d594fSAndroid Build Coastguard Worker     return new MemoryToolMallocSpace<DlMallocSpace, kDefaultMemoryToolRedZoneBytes, true, false>(
138*795d594fSAndroid Build Coastguard Worker         std::move(mem_map),
139*795d594fSAndroid Build Coastguard Worker         initial_size,
140*795d594fSAndroid Build Coastguard Worker         name,
141*795d594fSAndroid Build Coastguard Worker         mspace,
142*795d594fSAndroid Build Coastguard Worker         begin,
143*795d594fSAndroid Build Coastguard Worker         end,
144*795d594fSAndroid Build Coastguard Worker         begin + capacity, growth_limit,
145*795d594fSAndroid Build Coastguard Worker         can_move_objects,
146*795d594fSAndroid Build Coastguard Worker         starting_size);
147*795d594fSAndroid Build Coastguard Worker   } else {
148*795d594fSAndroid Build Coastguard Worker     return new DlMallocSpace(std::move(mem_map),
149*795d594fSAndroid Build Coastguard Worker                              initial_size,
150*795d594fSAndroid Build Coastguard Worker                              name,
151*795d594fSAndroid Build Coastguard Worker                              mspace,
152*795d594fSAndroid Build Coastguard Worker                              begin,
153*795d594fSAndroid Build Coastguard Worker                              end,
154*795d594fSAndroid Build Coastguard Worker                              begin + capacity,
155*795d594fSAndroid Build Coastguard Worker                              growth_limit,
156*795d594fSAndroid Build Coastguard Worker                              can_move_objects,
157*795d594fSAndroid Build Coastguard Worker                              starting_size);
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker 
Create(const std::string & name,size_t initial_size,size_t growth_limit,size_t capacity,bool can_move_objects)161*795d594fSAndroid Build Coastguard Worker DlMallocSpace* DlMallocSpace::Create(const std::string& name,
162*795d594fSAndroid Build Coastguard Worker                                      size_t initial_size,
163*795d594fSAndroid Build Coastguard Worker                                      size_t growth_limit,
164*795d594fSAndroid Build Coastguard Worker                                      size_t capacity,
165*795d594fSAndroid Build Coastguard Worker                                      bool can_move_objects) {
166*795d594fSAndroid Build Coastguard Worker   uint64_t start_time = 0;
167*795d594fSAndroid Build Coastguard Worker   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
168*795d594fSAndroid Build Coastguard Worker     start_time = NanoTime();
169*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "DlMallocSpace::Create entering " << name
170*795d594fSAndroid Build Coastguard Worker         << " initial_size=" << PrettySize(initial_size)
171*795d594fSAndroid Build Coastguard Worker         << " growth_limit=" << PrettySize(growth_limit)
172*795d594fSAndroid Build Coastguard Worker         << " capacity=" << PrettySize(capacity);
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker   // Memory we promise to dlmalloc before it asks for morecore.
176*795d594fSAndroid Build Coastguard Worker   // Note: making this value large means that large allocations are unlikely to succeed as dlmalloc
177*795d594fSAndroid Build Coastguard Worker   // will ask for this memory from sys_alloc which will fail as the footprint (this value plus the
178*795d594fSAndroid Build Coastguard Worker   // size of the large allocation) will be greater than the footprint limit.
179*795d594fSAndroid Build Coastguard Worker   size_t starting_size = gPageSize;
180*795d594fSAndroid Build Coastguard Worker   MemMap mem_map = CreateMemMap(name, starting_size, &initial_size, &growth_limit, &capacity);
181*795d594fSAndroid Build Coastguard Worker   if (!mem_map.IsValid()) {
182*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Failed to create mem map for alloc space (" << name << ") of size "
183*795d594fSAndroid Build Coastguard Worker                << PrettySize(capacity);
184*795d594fSAndroid Build Coastguard Worker     return nullptr;
185*795d594fSAndroid Build Coastguard Worker   }
186*795d594fSAndroid Build Coastguard Worker   DlMallocSpace* space = CreateFromMemMap(std::move(mem_map),
187*795d594fSAndroid Build Coastguard Worker                                           name,
188*795d594fSAndroid Build Coastguard Worker                                           starting_size,
189*795d594fSAndroid Build Coastguard Worker                                           initial_size,
190*795d594fSAndroid Build Coastguard Worker                                           growth_limit,
191*795d594fSAndroid Build Coastguard Worker                                           capacity,
192*795d594fSAndroid Build Coastguard Worker                                           can_move_objects);
193*795d594fSAndroid Build Coastguard Worker   // We start out with only the initial size possibly containing objects.
194*795d594fSAndroid Build Coastguard Worker   if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
195*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "DlMallocSpace::Create exiting (" << PrettyDuration(NanoTime() - start_time)
196*795d594fSAndroid Build Coastguard Worker         << " ) " << *space;
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker   return space;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker 
CreateMspace(void * begin,size_t morecore_start,size_t initial_size)201*795d594fSAndroid Build Coastguard Worker void* DlMallocSpace::CreateMspace(void* begin, size_t morecore_start, size_t initial_size) {
202*795d594fSAndroid Build Coastguard Worker   // clear errno to allow PLOG on error
203*795d594fSAndroid Build Coastguard Worker   errno = 0;
204*795d594fSAndroid Build Coastguard Worker   // create mspace using our backing storage starting at begin and with a footprint of
205*795d594fSAndroid Build Coastguard Worker   // morecore_start. Don't use an internal dlmalloc lock (as we already hold heap lock). When
206*795d594fSAndroid Build Coastguard Worker   // morecore_start bytes of memory is exhaused morecore will be called.
207*795d594fSAndroid Build Coastguard Worker   void* msp = create_mspace_with_base(begin, morecore_start, 0 /*locked*/);
208*795d594fSAndroid Build Coastguard Worker   if (msp != nullptr) {
209*795d594fSAndroid Build Coastguard Worker     // Do not allow morecore requests to succeed beyond the initial size of the heap
210*795d594fSAndroid Build Coastguard Worker     mspace_set_footprint_limit(msp, initial_size);
211*795d594fSAndroid Build Coastguard Worker   } else {
212*795d594fSAndroid Build Coastguard Worker     PLOG(ERROR) << "create_mspace_with_base failed";
213*795d594fSAndroid Build Coastguard Worker   }
214*795d594fSAndroid Build Coastguard Worker   return msp;
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
AllocWithGrowth(Thread * self,size_t num_bytes,size_t * bytes_allocated,size_t * usable_size,size_t * bytes_tl_bulk_allocated)217*795d594fSAndroid Build Coastguard Worker mirror::Object* DlMallocSpace::AllocWithGrowth(Thread* self, size_t num_bytes,
218*795d594fSAndroid Build Coastguard Worker                                                size_t* bytes_allocated, size_t* usable_size,
219*795d594fSAndroid Build Coastguard Worker                                                size_t* bytes_tl_bulk_allocated) {
220*795d594fSAndroid Build Coastguard Worker   mirror::Object* result;
221*795d594fSAndroid Build Coastguard Worker   {
222*795d594fSAndroid Build Coastguard Worker     MutexLock mu(self, lock_);
223*795d594fSAndroid Build Coastguard Worker     // Grow as much as possible within the space.
224*795d594fSAndroid Build Coastguard Worker     size_t max_allowed = Capacity();
225*795d594fSAndroid Build Coastguard Worker     mspace_set_footprint_limit(mspace_, max_allowed);
226*795d594fSAndroid Build Coastguard Worker     // Try the allocation.
227*795d594fSAndroid Build Coastguard Worker     result = AllocWithoutGrowthLocked(self, num_bytes, bytes_allocated, usable_size,
228*795d594fSAndroid Build Coastguard Worker                                       bytes_tl_bulk_allocated);
229*795d594fSAndroid Build Coastguard Worker     // Shrink back down as small as possible.
230*795d594fSAndroid Build Coastguard Worker     size_t footprint = mspace_footprint(mspace_);
231*795d594fSAndroid Build Coastguard Worker     mspace_set_footprint_limit(mspace_, footprint);
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker   if (result != nullptr) {
234*795d594fSAndroid Build Coastguard Worker     // Zero freshly allocated memory, done while not holding the space's lock.
235*795d594fSAndroid Build Coastguard Worker     memset(result, 0, num_bytes);
236*795d594fSAndroid Build Coastguard Worker     // Check that the result is contained in the space.
237*795d594fSAndroid Build Coastguard Worker     CHECK_IMPLIES(kDebugSpaces, Contains(result));
238*795d594fSAndroid Build Coastguard Worker   }
239*795d594fSAndroid Build Coastguard Worker   return result;
240*795d594fSAndroid Build Coastguard Worker }
241*795d594fSAndroid Build Coastguard Worker 
CreateInstance(MemMap && mem_map,const std::string & name,void * allocator,uint8_t * begin,uint8_t * end,uint8_t * limit,size_t growth_limit,bool can_move_objects)242*795d594fSAndroid Build Coastguard Worker MallocSpace* DlMallocSpace::CreateInstance(MemMap&& mem_map,
243*795d594fSAndroid Build Coastguard Worker                                            const std::string& name,
244*795d594fSAndroid Build Coastguard Worker                                            void* allocator,
245*795d594fSAndroid Build Coastguard Worker                                            uint8_t* begin,
246*795d594fSAndroid Build Coastguard Worker                                            uint8_t* end,
247*795d594fSAndroid Build Coastguard Worker                                            uint8_t* limit,
248*795d594fSAndroid Build Coastguard Worker                                            size_t growth_limit,
249*795d594fSAndroid Build Coastguard Worker                                            bool can_move_objects) {
250*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current()->IsRunningOnMemoryTool()) {
251*795d594fSAndroid Build Coastguard Worker     return new MemoryToolMallocSpace<DlMallocSpace, kDefaultMemoryToolRedZoneBytes, true, false>(
252*795d594fSAndroid Build Coastguard Worker         std::move(mem_map),
253*795d594fSAndroid Build Coastguard Worker         initial_size_,
254*795d594fSAndroid Build Coastguard Worker         name,
255*795d594fSAndroid Build Coastguard Worker         allocator,
256*795d594fSAndroid Build Coastguard Worker         begin,
257*795d594fSAndroid Build Coastguard Worker         end,
258*795d594fSAndroid Build Coastguard Worker         limit,
259*795d594fSAndroid Build Coastguard Worker         growth_limit,
260*795d594fSAndroid Build Coastguard Worker         can_move_objects,
261*795d594fSAndroid Build Coastguard Worker         starting_size_);
262*795d594fSAndroid Build Coastguard Worker   } else {
263*795d594fSAndroid Build Coastguard Worker     return new DlMallocSpace(std::move(mem_map),
264*795d594fSAndroid Build Coastguard Worker                              initial_size_,
265*795d594fSAndroid Build Coastguard Worker                              name,
266*795d594fSAndroid Build Coastguard Worker                              allocator,
267*795d594fSAndroid Build Coastguard Worker                              begin,
268*795d594fSAndroid Build Coastguard Worker                              end,
269*795d594fSAndroid Build Coastguard Worker                              limit,
270*795d594fSAndroid Build Coastguard Worker                              growth_limit,
271*795d594fSAndroid Build Coastguard Worker                              can_move_objects,
272*795d594fSAndroid Build Coastguard Worker                              starting_size_);
273*795d594fSAndroid Build Coastguard Worker   }
274*795d594fSAndroid Build Coastguard Worker }
275*795d594fSAndroid Build Coastguard Worker 
Free(Thread * self,mirror::Object * ptr)276*795d594fSAndroid Build Coastguard Worker size_t DlMallocSpace::Free(Thread* self, mirror::Object* ptr) {
277*795d594fSAndroid Build Coastguard Worker   MutexLock mu(self, lock_);
278*795d594fSAndroid Build Coastguard Worker   if (kDebugSpaces) {
279*795d594fSAndroid Build Coastguard Worker     CHECK(ptr != nullptr);
280*795d594fSAndroid Build Coastguard Worker     CHECK(Contains(ptr)) << "Free (" << ptr << ") not in bounds of heap " << *this;
281*795d594fSAndroid Build Coastguard Worker   }
282*795d594fSAndroid Build Coastguard Worker   const size_t bytes_freed = AllocationSizeNonvirtual(ptr, nullptr);
283*795d594fSAndroid Build Coastguard Worker   if (kRecentFreeCount > 0) {
284*795d594fSAndroid Build Coastguard Worker     RegisterRecentFree(ptr);
285*795d594fSAndroid Build Coastguard Worker   }
286*795d594fSAndroid Build Coastguard Worker   mspace_free(mspace_, ptr);
287*795d594fSAndroid Build Coastguard Worker   return bytes_freed;
288*795d594fSAndroid Build Coastguard Worker }
289*795d594fSAndroid Build Coastguard Worker 
FreeList(Thread * self,size_t num_ptrs,mirror::Object ** ptrs)290*795d594fSAndroid Build Coastguard Worker size_t DlMallocSpace::FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
291*795d594fSAndroid Build Coastguard Worker   DCHECK(ptrs != nullptr);
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   // Don't need the lock to calculate the size of the freed pointers.
294*795d594fSAndroid Build Coastguard Worker   size_t bytes_freed = 0;
295*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < num_ptrs; i++) {
296*795d594fSAndroid Build Coastguard Worker     mirror::Object* ptr = ptrs[i];
297*795d594fSAndroid Build Coastguard Worker     const size_t look_ahead = 8;
298*795d594fSAndroid Build Coastguard Worker     if (kPrefetchDuringDlMallocFreeList && i + look_ahead < num_ptrs) {
299*795d594fSAndroid Build Coastguard Worker       // The head of chunk for the allocation is sizeof(size_t) behind the allocation.
300*795d594fSAndroid Build Coastguard Worker       __builtin_prefetch(reinterpret_cast<char*>(ptrs[i + look_ahead]) - sizeof(size_t));
301*795d594fSAndroid Build Coastguard Worker     }
302*795d594fSAndroid Build Coastguard Worker     bytes_freed += AllocationSizeNonvirtual(ptr, nullptr);
303*795d594fSAndroid Build Coastguard Worker   }
304*795d594fSAndroid Build Coastguard Worker 
305*795d594fSAndroid Build Coastguard Worker   if (kRecentFreeCount > 0) {
306*795d594fSAndroid Build Coastguard Worker     MutexLock mu(self, lock_);
307*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_ptrs; i++) {
308*795d594fSAndroid Build Coastguard Worker       RegisterRecentFree(ptrs[i]);
309*795d594fSAndroid Build Coastguard Worker     }
310*795d594fSAndroid Build Coastguard Worker   }
311*795d594fSAndroid Build Coastguard Worker 
312*795d594fSAndroid Build Coastguard Worker   if (kDebugSpaces) {
313*795d594fSAndroid Build Coastguard Worker     size_t num_broken_ptrs = 0;
314*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < num_ptrs; i++) {
315*795d594fSAndroid Build Coastguard Worker       if (!Contains(ptrs[i])) {
316*795d594fSAndroid Build Coastguard Worker         num_broken_ptrs++;
317*795d594fSAndroid Build Coastguard Worker         LOG(ERROR) << "FreeList[" << i << "] (" << ptrs[i] << ") not in bounds of heap " << *this;
318*795d594fSAndroid Build Coastguard Worker       } else {
319*795d594fSAndroid Build Coastguard Worker         size_t size = mspace_usable_size(ptrs[i]);
320*795d594fSAndroid Build Coastguard Worker         memset(ptrs[i], 0xEF, size);
321*795d594fSAndroid Build Coastguard Worker       }
322*795d594fSAndroid Build Coastguard Worker     }
323*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(num_broken_ptrs, 0u);
324*795d594fSAndroid Build Coastguard Worker   }
325*795d594fSAndroid Build Coastguard Worker 
326*795d594fSAndroid Build Coastguard Worker   {
327*795d594fSAndroid Build Coastguard Worker     MutexLock mu(self, lock_);
328*795d594fSAndroid Build Coastguard Worker     mspace_bulk_free(mspace_, reinterpret_cast<void**>(ptrs), num_ptrs);
329*795d594fSAndroid Build Coastguard Worker     return bytes_freed;
330*795d594fSAndroid Build Coastguard Worker   }
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker 
Trim()333*795d594fSAndroid Build Coastguard Worker size_t DlMallocSpace::Trim() {
334*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
335*795d594fSAndroid Build Coastguard Worker   // Trim to release memory at the end of the space.
336*795d594fSAndroid Build Coastguard Worker   mspace_trim(mspace_, 0);
337*795d594fSAndroid Build Coastguard Worker   // Visit space looking for page-sized holes to advise the kernel we don't need.
338*795d594fSAndroid Build Coastguard Worker   size_t reclaimed = 0;
339*795d594fSAndroid Build Coastguard Worker   mspace_inspect_all(mspace_, DlmallocMadviseCallback, &reclaimed);
340*795d594fSAndroid Build Coastguard Worker   return reclaimed;
341*795d594fSAndroid Build Coastguard Worker }
342*795d594fSAndroid Build Coastguard Worker 
Walk(void (* callback)(void * start,void * end,size_t num_bytes,void * callback_arg),void * arg)343*795d594fSAndroid Build Coastguard Worker void DlMallocSpace::Walk(void(*callback)(void *start, void *end, size_t num_bytes, void* callback_arg),
344*795d594fSAndroid Build Coastguard Worker                       void* arg) {
345*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
346*795d594fSAndroid Build Coastguard Worker   mspace_inspect_all(mspace_, callback, arg);
347*795d594fSAndroid Build Coastguard Worker   callback(nullptr, nullptr, 0, arg);  // Indicate end of a space.
348*795d594fSAndroid Build Coastguard Worker }
349*795d594fSAndroid Build Coastguard Worker 
GetFootprint()350*795d594fSAndroid Build Coastguard Worker size_t DlMallocSpace::GetFootprint() {
351*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
352*795d594fSAndroid Build Coastguard Worker   return mspace_footprint(mspace_);
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker 
GetFootprintLimit()355*795d594fSAndroid Build Coastguard Worker size_t DlMallocSpace::GetFootprintLimit() {
356*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
357*795d594fSAndroid Build Coastguard Worker   return mspace_footprint_limit(mspace_);
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker 
SetFootprintLimit(size_t new_size)360*795d594fSAndroid Build Coastguard Worker void DlMallocSpace::SetFootprintLimit(size_t new_size) {
361*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
362*795d594fSAndroid Build Coastguard Worker   VLOG(heap) << "DlMallocSpace::SetFootprintLimit " << PrettySize(new_size);
363*795d594fSAndroid Build Coastguard Worker   // Compare against the actual footprint, rather than the Size(), because the heap may not have
364*795d594fSAndroid Build Coastguard Worker   // grown all the way to the allowed size yet.
365*795d594fSAndroid Build Coastguard Worker   size_t current_space_size = mspace_footprint(mspace_);
366*795d594fSAndroid Build Coastguard Worker   if (new_size < current_space_size) {
367*795d594fSAndroid Build Coastguard Worker     // Don't let the space grow any more.
368*795d594fSAndroid Build Coastguard Worker     new_size = current_space_size;
369*795d594fSAndroid Build Coastguard Worker   }
370*795d594fSAndroid Build Coastguard Worker   mspace_set_footprint_limit(mspace_, new_size);
371*795d594fSAndroid Build Coastguard Worker }
372*795d594fSAndroid Build Coastguard Worker 
GetBytesAllocated()373*795d594fSAndroid Build Coastguard Worker uint64_t DlMallocSpace::GetBytesAllocated() {
374*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
375*795d594fSAndroid Build Coastguard Worker   size_t bytes_allocated = 0;
376*795d594fSAndroid Build Coastguard Worker   mspace_inspect_all(mspace_, DlmallocBytesAllocatedCallback, &bytes_allocated);
377*795d594fSAndroid Build Coastguard Worker   return bytes_allocated;
378*795d594fSAndroid Build Coastguard Worker }
379*795d594fSAndroid Build Coastguard Worker 
GetObjectsAllocated()380*795d594fSAndroid Build Coastguard Worker uint64_t DlMallocSpace::GetObjectsAllocated() {
381*795d594fSAndroid Build Coastguard Worker   MutexLock mu(Thread::Current(), lock_);
382*795d594fSAndroid Build Coastguard Worker   size_t objects_allocated = 0;
383*795d594fSAndroid Build Coastguard Worker   mspace_inspect_all(mspace_, DlmallocObjectsAllocatedCallback, &objects_allocated);
384*795d594fSAndroid Build Coastguard Worker   return objects_allocated;
385*795d594fSAndroid Build Coastguard Worker }
386*795d594fSAndroid Build Coastguard Worker 
Clear()387*795d594fSAndroid Build Coastguard Worker void DlMallocSpace::Clear() {
388*795d594fSAndroid Build Coastguard Worker   size_t footprint_limit = GetFootprintLimit();
389*795d594fSAndroid Build Coastguard Worker   madvise(GetMemMap()->Begin(), GetMemMap()->Size(), MADV_DONTNEED);
390*795d594fSAndroid Build Coastguard Worker   live_bitmap_.Clear();
391*795d594fSAndroid Build Coastguard Worker   mark_bitmap_.Clear();
392*795d594fSAndroid Build Coastguard Worker   SetEnd(Begin() + starting_size_);
393*795d594fSAndroid Build Coastguard Worker   mspace_ = CreateMspace(mem_map_.Begin(), starting_size_, initial_size_);
394*795d594fSAndroid Build Coastguard Worker   SetFootprintLimit(footprint_limit);
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker 
397*795d594fSAndroid Build Coastguard Worker #ifndef NDEBUG
CheckMoreCoreForPrecondition()398*795d594fSAndroid Build Coastguard Worker void DlMallocSpace::CheckMoreCoreForPrecondition() {
399*795d594fSAndroid Build Coastguard Worker   lock_.AssertHeld(Thread::Current());
400*795d594fSAndroid Build Coastguard Worker }
401*795d594fSAndroid Build Coastguard Worker #endif
402*795d594fSAndroid Build Coastguard Worker 
403*795d594fSAndroid Build Coastguard Worker struct MspaceCbArgs {
404*795d594fSAndroid Build Coastguard Worker   size_t max_contiguous;
405*795d594fSAndroid Build Coastguard Worker   size_t used;
406*795d594fSAndroid Build Coastguard Worker };
407*795d594fSAndroid Build Coastguard Worker 
MSpaceChunkCallback(void * start,void * end,size_t used_bytes,void * arg)408*795d594fSAndroid Build Coastguard Worker static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* arg) {
409*795d594fSAndroid Build Coastguard Worker   size_t chunk_size = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start);
410*795d594fSAndroid Build Coastguard Worker   MspaceCbArgs* mspace_cb_args = reinterpret_cast<MspaceCbArgs*>(arg);
411*795d594fSAndroid Build Coastguard Worker   mspace_cb_args->used += used_bytes;
412*795d594fSAndroid Build Coastguard Worker   if (used_bytes < chunk_size) {
413*795d594fSAndroid Build Coastguard Worker     size_t chunk_free_bytes = chunk_size - used_bytes;
414*795d594fSAndroid Build Coastguard Worker     size_t& max_contiguous_allocation = mspace_cb_args->max_contiguous;
415*795d594fSAndroid Build Coastguard Worker     max_contiguous_allocation = std::max(max_contiguous_allocation, chunk_free_bytes);
416*795d594fSAndroid Build Coastguard Worker   }
417*795d594fSAndroid Build Coastguard Worker }
418*795d594fSAndroid Build Coastguard Worker 
LogFragmentationAllocFailure(std::ostream & os,size_t failed_alloc_bytes)419*795d594fSAndroid Build Coastguard Worker bool DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os,
420*795d594fSAndroid Build Coastguard Worker                                                  size_t failed_alloc_bytes) {
421*795d594fSAndroid Build Coastguard Worker   Thread* const self = Thread::Current();
422*795d594fSAndroid Build Coastguard Worker   MspaceCbArgs mspace_cb_args = {0, 0};
423*795d594fSAndroid Build Coastguard Worker   // To allow the Walk/InspectAll() to exclusively-lock the mutator
424*795d594fSAndroid Build Coastguard Worker   // lock, temporarily release the shared access to the mutator
425*795d594fSAndroid Build Coastguard Worker   // lock here by transitioning to the suspended state.
426*795d594fSAndroid Build Coastguard Worker   Locks::mutator_lock_->AssertSharedHeld(self);
427*795d594fSAndroid Build Coastguard Worker   ScopedThreadSuspension sts(self, ThreadState::kSuspended);
428*795d594fSAndroid Build Coastguard Worker   Walk(MSpaceChunkCallback, &mspace_cb_args);
429*795d594fSAndroid Build Coastguard Worker   if (failed_alloc_bytes > mspace_cb_args.max_contiguous) {
430*795d594fSAndroid Build Coastguard Worker     os << "; failed due to malloc_space fragmentation (largest possible contiguous allocation "
431*795d594fSAndroid Build Coastguard Worker        << mspace_cb_args.max_contiguous << " bytes, space in use " << mspace_cb_args.used
432*795d594fSAndroid Build Coastguard Worker        << " bytes, capacity = " << Capacity() << ")";
433*795d594fSAndroid Build Coastguard Worker     return true;
434*795d594fSAndroid Build Coastguard Worker   }
435*795d594fSAndroid Build Coastguard Worker   return false;
436*795d594fSAndroid Build Coastguard Worker }
437*795d594fSAndroid Build Coastguard Worker 
438*795d594fSAndroid Build Coastguard Worker }  // namespace space
439*795d594fSAndroid Build Coastguard Worker 
440*795d594fSAndroid Build Coastguard Worker namespace allocator {
441*795d594fSAndroid Build Coastguard Worker 
442*795d594fSAndroid Build Coastguard Worker // Implement the dlmalloc morecore callback.
ArtDlMallocMoreCore(void * mspace,intptr_t increment)443*795d594fSAndroid Build Coastguard Worker void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) REQUIRES_SHARED(Locks::mutator_lock_) {
444*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
445*795d594fSAndroid Build Coastguard Worker   Heap* heap = runtime->GetHeap();
446*795d594fSAndroid Build Coastguard Worker   ::art::gc::space::DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace();
447*795d594fSAndroid Build Coastguard Worker   // Support for multiple DlMalloc provided by a slow path.
448*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(dlmalloc_space == nullptr || dlmalloc_space->GetMspace() != mspace)) {
449*795d594fSAndroid Build Coastguard Worker     if (LIKELY(runtime->GetJitCodeCache() != nullptr)) {
450*795d594fSAndroid Build Coastguard Worker       jit::JitCodeCache* code_cache = runtime->GetJitCodeCache();
451*795d594fSAndroid Build Coastguard Worker       if (code_cache->OwnsSpace(mspace)) {
452*795d594fSAndroid Build Coastguard Worker         return code_cache->MoreCore(mspace, increment);
453*795d594fSAndroid Build Coastguard Worker       }
454*795d594fSAndroid Build Coastguard Worker     }
455*795d594fSAndroid Build Coastguard Worker     dlmalloc_space = nullptr;
456*795d594fSAndroid Build Coastguard Worker     for (space::ContinuousSpace* space : heap->GetContinuousSpaces()) {
457*795d594fSAndroid Build Coastguard Worker       if (space->IsDlMallocSpace()) {
458*795d594fSAndroid Build Coastguard Worker         ::art::gc::space::DlMallocSpace* cur_dlmalloc_space = space->AsDlMallocSpace();
459*795d594fSAndroid Build Coastguard Worker         if (cur_dlmalloc_space->GetMspace() == mspace) {
460*795d594fSAndroid Build Coastguard Worker           dlmalloc_space = cur_dlmalloc_space;
461*795d594fSAndroid Build Coastguard Worker           break;
462*795d594fSAndroid Build Coastguard Worker         }
463*795d594fSAndroid Build Coastguard Worker       }
464*795d594fSAndroid Build Coastguard Worker     }
465*795d594fSAndroid Build Coastguard Worker     CHECK(dlmalloc_space != nullptr) << "Couldn't find DlmMallocSpace with mspace=" << mspace;
466*795d594fSAndroid Build Coastguard Worker   }
467*795d594fSAndroid Build Coastguard Worker   return dlmalloc_space->MoreCore(increment);
468*795d594fSAndroid Build Coastguard Worker }
469*795d594fSAndroid Build Coastguard Worker 
470*795d594fSAndroid Build Coastguard Worker }  // namespace allocator
471*795d594fSAndroid Build Coastguard Worker 
472*795d594fSAndroid Build Coastguard Worker }  // namespace gc
473*795d594fSAndroid Build Coastguard Worker }  // namespace art
474