def __init__(self, objects, rootset, free_list, settings): self.settings = settings self.objects = objects self.rootset = rootset self.free_list = free_list self.settings.heap_size = self.settings.heap_size // 2 # represents size of half heap self.new_space = FreeListNode(0, settings.heap_size) self.old_space = FreeListNode(settings.heap_size, settings.heap_size) self.free_list.clear() self.free_list.append(copy(self.new_space)) self.bytes_copied = 0
def test_swap_spaces(mock_settings): objects = {} rootset = set() free_list = [FreeListNode(0, mock_settings.heap_size)] collector = CopyingGC(objects, rootset, free_list, settings=mock_settings) # Initially use first half of heap assert len(free_list) == 1 assert free_list[0].heap_index == 0 assert free_list[0].num_bytes == 50 collector.swap_spaces() # swap to second half assert len(free_list) == 1 assert free_list[0].heap_index == 50 assert free_list[0].num_bytes == 50 collector.swap_spaces() # back to first half again assert len(free_list) == 1 assert free_list[0].heap_index == 0 assert free_list[0].num_bytes == 50
def free(self, object_id): obj = self.objects.pop(object_id) add_node(self.free_list, FreeListNode(obj.heap_index, obj.size)) for p in obj.pointers: child = self.objects.get(p) if child: child.referenceCount = child.referenceCount-1 if child.referenceCount == 0: self.free(p)
def allocate(self, num_bytes): for index, node in enumerate(self.free_list): if node.num_bytes >= num_bytes: self.free_list.pop(index) if node.num_bytes > num_bytes: new_node = FreeListNode(node.heap_index + num_bytes, node.num_bytes - num_bytes) # target for future optimization, I know exactly where it goes add_node(self.free_list, new_node) return node.heap_index raise OutOfMemoryException
def test_collected_objects_get_copied(mock_settings): o = HeapObject(0, 8) objects = {1: o} rootset = set([1]) free_list = [FreeListNode(0, mock_settings.heap_size)] collector = CopyingGC(objects, rootset, free_list, settings=mock_settings) collector.collect() assert o.heap_index == 50 assert o.size == 8
def test_free_space_accounts_for_live_objects(mock_settings): o = HeapObject(0, 8) objects = {1: o} rootset = set([1]) free_list = [FreeListNode(0, mock_settings.heap_size)] collector = CopyingGC(objects, rootset, free_list, settings=mock_settings) collector.collect() assert len(free_list) == 1 assert free_list[0].heap_index == 58 assert free_list[0].num_bytes == 42
def allocate(self, num_bytes): for i in range(len(self.free_list)): index = (self.current_index + i) % len(self.free_list) node = self.free_list[index] if node.num_bytes >= num_bytes: self.free_list.pop(index) if node.num_bytes > num_bytes: new_node = FreeListNode(node.heap_index + num_bytes, node.num_bytes - num_bytes) add_node(self.free_list, new_node) self.current_index = index return node.heap_index raise OutOfMemoryException
def __init__(self, allocator_class, collector_class, write_barrier_classes, settings): self.settings = settings self.free_list = [FreeListNode(0, settings.heap_size)] self.objects = {} self.rootset = set() self.allocator = allocator_class(self.free_list, settings) self.collector = collector_class(self.objects, self.rootset, self.free_list, settings) self.write_barriers = [] for barrier_class in write_barrier_classes: self.write_barriers.append( barrier_class(self.objects, self.rootset, self.free_list, settings)) self.stats_generator = FreeListStatsGenerator(settings, self.free_list)
def test_heap_doesnt_grows_when_insufficient_utilization(mock_settings): mock_settings.heap_size = 100 mock_settings.high_water_percent = 50 mock_settings.growth_factor = 2.0 o1 = HeapObject(0, 8) objects = {1: o1} rootset = set([1]) free_list = [FreeListNode(8, 92)] collector = MarkSweepGrowGC(objects, rootset, free_list, settings=mock_settings) collector.collect() # Heap utilization is only 8%, heap should not grow assert mock_settings.heap_size == 100
def test_heap_grows_when_sufficient_utilization(mock_settings): mock_settings.heap_size = 100 mock_settings.high_water_percent = 50 mock_settings.growth_factor = 2.0 o1 = HeapObject(0, 80) objects = {1: o1} rootset = set([1]) free_list = [FreeListNode(80, 20)] collector = MarkSweepGrowGC(objects, rootset, free_list, settings=mock_settings) collector.collect() # Heap utilization is 80%, heap should grow by 2.0x assert mock_settings.heap_size == 200
def test_percent_when_heap_partial(mock_settings): n1 = FreeListNode(0,22) n2 = FreeListNode(50,14) s = FreeListStatsGenerator(mock_settings, [n1, n2]) assert s.percent_free() == 36 assert s.percent_used() == 64
def free_list(): n1 = FreeListNode(0, 1) n2 = FreeListNode(2, 1) n3 = FreeListNode(6, 1) return [n1, n2, n3]
def test_three_adjacent_nodes_are_merged(free_list): n = FreeListNode(3, 3) add_node(free_list, n) assert len(free_list) == 2 assert free_list[1].heap_index == 2 assert free_list[1].num_bytes == 5
def test_proceeding_adjacent_nodes_are_merged(free_list): n = FreeListNode(5, 1) add_node(free_list, n) assert len(free_list) == 3 assert free_list[2].heap_index == 5 assert free_list[2].num_bytes == 2
def test_maintains_ascending_heap_order(free_list): n = FreeListNode(4, 1) add_node(free_list, n) assert len(free_list) == 4 assert free_list[2] == n
def allocator(): n1 = FreeListNode(0, 1) n2 = FreeListNode(2, 3) n3 = FreeListNode(9, 3) return NextFitAllocator([n1, n2, n3], settings=None)
def free(self, object_id): obj = self.objects.pop(object_id) add_node(self.free_list, FreeListNode(obj.heap_index, obj.size))
def node(): return FreeListNode(2, 1)
def test_adjacent_node_before(node): n = FreeListNode(1, 1) assert node.adjacent_to(n)
def test_percent_when_heap_empty(mock_settings): n = FreeListNode(0,100) s = FreeListStatsGenerator(mock_settings, [n]) assert s.percent_free() == 100 assert s.percent_used() == 0
def test_average_node_size(mock_settings): n1 = FreeListNode(0,10) n2 = FreeListNode(40,30) n3 = FreeListNode(80,20) s = FreeListStatsGenerator(mock_settings, [n1, n2, n3]) assert s.average_node_size() == 20
def test_unadjacent_node_after(node): n = FreeListNode(4, 1) assert not node.adjacent_to(n)