def double_space_size(self): self.red_zone = 0 old_fromspace = self.fromspace newsize = self.space_size * 2 newspace = llarena.arena_malloc(newsize, True) if not newspace: return False # out of memory llarena.arena_free(old_fromspace) self.fromspace = newspace # now self.tospace contains the existing objects and # self.fromspace is the freshly allocated bigger space self.semispace_collect(size_changing=True) self.top_of_space = self.tospace + newsize # now self.tospace is the freshly allocated bigger space, # and self.fromspace is the old smaller space, now empty llarena.arena_free(self.fromspace) newspace = llarena.arena_malloc(newsize, True) if not newspace: # Complex failure case: we have in self.tospace a big chunk # of memory, and the two smaller original spaces are already gone. # Unsure if it's worth these efforts, but we can artificially # split self.tospace in two again... self.max_space_size = self.space_size # don't try to grow again, # because doing arena_free(self.fromspace) would crash self.fromspace = self.tospace + self.space_size self.top_of_space = self.fromspace ll_assert(self.free <= self.top_of_space, "unexpected growth of GC space usage during collect") return False # out of memory self.fromspace = newspace self.space_size = newsize return True # success
def mass_free(self, ok_to_free_func): objs = self.all_objects self.all_objects = [] self.total_memory_used = 0 for rawobj, nsize in objs: if ok_to_free_func(rawobj): llarena.arena_free(rawobj) else: self.all_objects.append((rawobj, nsize)) self.total_memory_used += nsize
def mass_free(self, ok_to_free_func): """For each object, if ok_to_free_func(obj) returns True, then free the object. """ self.total_memory_used = r_uint(0) # # For each size class: size_class = self.small_request_threshold >> WORD_POWER_2 while size_class >= 1: # # Walk the pages in 'page_for_size[size_class]' and # 'full_page_for_size[size_class]' and free some objects. # Pages completely freed are added to 'page.arena.freepages', # and become available for reuse by any size class. Pages # not completely freed are re-chained either in # 'full_page_for_size[]' or 'page_for_size[]'. self.mass_free_in_pages(size_class, ok_to_free_func) # size_class -= 1 # # Rehash arenas into the correct arenas_lists[i]. If # 'self.current_arena' contains an arena too, it remains there. (self.old_arenas_lists, self.arenas_lists) = ( self.arenas_lists, self.old_arenas_lists) # i = 0 while i < self.max_pages_per_arena: self.arenas_lists[i] = ARENA_NULL i += 1 # i = 0 while i < self.max_pages_per_arena: arena = self.old_arenas_lists[i] while arena != ARENA_NULL: nextarena = arena.nextarena # if arena.nfreepages == arena.totalpages: # # The whole arena is empty. Free it. llarena.arena_free(arena.base) lltype.free(arena, flavor='raw', track_allocation=False) # else: # Insert 'arena' in the correct arenas_lists[n] n = arena.nfreepages ll_assert(n < self.max_pages_per_arena, "totalpages != nfreepages >= max_pages_per_arena") arena.nextarena = self.arenas_lists[n] self.arenas_lists[n] = arena # arena = nextarena i += 1 # self.min_empty_nfreepages = 1
def mass_free_incremental(self, ok_to_free_func, max_pages): old = self.old_all_objects while old: rawobj, nsize = old.pop() if ok_to_free_func(rawobj): llarena.arena_free(rawobj) else: self.all_objects.append((rawobj, nsize)) self.total_memory_used += nsize max_pages -= 0.1 if max_pages <= 0: return False return True
def test_look_inside_object(): # this code is also used in translation tests below myarenasize = 50 a = arena_malloc(myarenasize, False) b = a + round_up_for_allocation(llmemory.sizeof(lltype.Char)) arena_reserve(b, precomputed_size) (b + llmemory.offsetof(SX, 'x')).signed[0] = 123 assert llmemory.cast_adr_to_ptr(b, SPTR).x == 123 llmemory.cast_adr_to_ptr(b, SPTR).x += 1 assert (b + llmemory.offsetof(SX, 'x')).signed[0] == 124 arena_reset(a, myarenasize, True) arena_reserve(b, round_up_for_allocation(llmemory.sizeof(SX))) assert llmemory.cast_adr_to_ptr(b, SPTR).x == 0 arena_free(a) return 42
def _rehash_arenas_lists(self): # # Rehash arenas into the correct arenas_lists[i]. If # 'self.current_arena' contains an arena too, it remains there. (self.old_arenas_lists, self.arenas_lists) = (self.arenas_lists, self.old_arenas_lists) # i = 0 while i < self.max_pages_per_arena: self.arenas_lists[i] = ARENA_NULL i += 1 # i = 0 while i < self.max_pages_per_arena: arena = self.old_arenas_lists[i] while arena != ARENA_NULL: nextarena = arena.nextarena # if arena.nfreepages == arena.totalpages: # # The whole arena is empty. Free it. llarena.arena_reset(arena.base, self.arena_size, 4) llarena.arena_free(arena.base) self.total_memory_alloced -= self.arena_size lltype.free(arena, flavor='raw', track_allocation=False) self.arenas_count -= 1 # else: # Insert 'arena' in the correct arenas_lists[n] n = arena.nfreepages ll_assert( n < self.max_pages_per_arena, "totalpages != nfreepages >= max_pages_per_arena") arena.nextarena = self.arenas_lists[n] self.arenas_lists[n] = arena # arena = nextarena i += 1 # self.min_empty_nfreepages = 1
def _rehash_arenas_lists(self): # # Rehash arenas into the correct arenas_lists[i]. If # 'self.current_arena' contains an arena too, it remains there. (self.old_arenas_lists, self.arenas_lists) = ( self.arenas_lists, self.old_arenas_lists) # i = 0 while i < self.max_pages_per_arena: self.arenas_lists[i] = ARENA_NULL i += 1 # i = 0 while i < self.max_pages_per_arena: arena = self.old_arenas_lists[i] while arena != ARENA_NULL: nextarena = arena.nextarena # if arena.nfreepages == arena.totalpages: # # The whole arena is empty. Free it. llarena.arena_reset(arena.base, self.arena_size, 4) llarena.arena_free(arena.base) lltype.free(arena, flavor='raw', track_allocation=False) # else: # Insert 'arena' in the correct arenas_lists[n] n = arena.nfreepages ll_assert(n < self.max_pages_per_arena, "totalpages != nfreepages >= max_pages_per_arena") arena.nextarena = self.arenas_lists[n] self.arenas_lists[n] = arena # arena = nextarena i += 1 # self.min_empty_nfreepages = 1
def _teardown(self): debug_print("Teardown") llarena.arena_free(self.fromspace) llarena.arena_free(self.tospace)
def f(): a = llarena.arena_malloc(800, False) llarena.arena_reset(a, 800, 2) llarena.arena_free(a)