def test_global_gc(shutdown_only): cluster = ray.cluster_utils.Cluster() cluster.add_node( num_cpus=1, num_gpus=0, _system_config={ "local_gc_interval_s": 10, "local_gc_min_interval_s": 5, "global_gc_min_interval_s": 10 }) cluster.add_node(num_cpus=1, num_gpus=0) ray.init(address=cluster.address) class ObjectWithCyclicRef: def __init__(self): self.loop = self @ray.remote(num_cpus=1) class GarbageHolder: def __init__(self): gc.disable() x = ObjectWithCyclicRef() self.garbage = weakref.ref(x) def has_garbage(self): return self.garbage() is not None try: gc.disable() # Local driver. local_ref = weakref.ref(ObjectWithCyclicRef()) # Remote workers. actors = [GarbageHolder.remote() for _ in range(2)] assert local_ref() is not None assert all(ray.get([a.has_garbage.remote() for a in actors])) # GC should be triggered for all workers, including the local driver. global_gc() def check_refs_gced(): return (local_ref() is None and not any(ray.get([a.has_garbage.remote() for a in actors]))) wait_for_condition(check_refs_gced, timeout=30) finally: gc.enable()
def test_global_gc(shutdown_only): cluster = ray.cluster_utils.Cluster() for _ in range(2): cluster.add_node(num_cpus=1, num_gpus=0) ray.init(address=cluster.address) class ObjectWithCyclicRef: def __init__(self): self.loop = self @ray.remote(num_cpus=1) class GarbageHolder: def __init__(self): gc.disable() x = ObjectWithCyclicRef() self.garbage = weakref.ref(x) def has_garbage(self): return self.garbage() is not None try: gc.disable() # Local driver. local_ref = weakref.ref(ObjectWithCyclicRef()) # Remote workers. actors = [GarbageHolder.remote() for _ in range(2)] assert local_ref() is not None assert all(ray.get([a.has_garbage.remote() for a in actors])) # GC should be triggered for all workers, including the local driver. global_gc() time.sleep(1) assert local_ref() is None assert not any(ray.get([a.has_garbage.remote() for a in actors])) finally: gc.enable()