问题描述
我已经创建了一个自定义 NSGA2 算法,并且我正在为我的评估器使用 ray。我注意到我从 ray 任务中检索到的对象被固定,我尝试做一些事情,例如复制返回的对象并删除对原始对象的引用,使用垃圾收集器,或者只是删除对 ray 的所有引用对象使用后但没有运气。
使用光线内存时,我多次获得此输出(从每次评估迭代中):
Driver f7dc3a80d7a578ceffffffffffffffffffffffff0100000001000000 47.9 MiB PINNED_IN_MEMORY /root/anaconda3/envs/myenv/lib/python3.8/site-packages/ray/_private/client_mode_hook.py:wrapper:62 | Optimizer/components.py:evaluate_all:511 | Optimizer/components.py:evaluate_all:159 | Optimizer/components.py:iterate:134
class MapEvaluator:
def __init__(...):
def evaluate_all(...):
....
results = []
for i in range(len(chromosomes)):
trial_idx = int(n_gen*population_size) + i
offspring[i].trial_idx = trial_idx
results.append(get_genes.remote(predictor,chromosomes[i],trial_idx,n_gen))
chromosomes,evaluation,updates_pgScanCaseRate,cache = zip(*ray.get([result for result in results])) # this is line 511 from the above output
.....
del chromosomes,cache
....
return offspring
然后它会做一些工作并返回一个对象,该对象引用了从 ray 中检索到的一些对象。我尝试复制需要返回的对象,但似乎不起作用。
2&3)
class NSGAII:
def __init__(...):
....
def iterate(...):
....
offspring = self.evaluate_all(parents) # calls function below # line 134 from ray memory output
offspring.extend(self.population)
def evaluate_all(...):
for parent in parents:
offspring.extend(self.evaluator.evaluate_all(parent,n_gen,self.variator,self.breeding,self.population_size)) # line 159 from ray memory output
#self.evaluator.evaluate_all calls the function from 1) from the evaluator class
主要问题是我按顺序运行 GA(即一个接一个地进行多次运行) 例如
for problem in problems:
run_optimization()
并且上次运行的对象被固定。我已经阅读了有关内存管理的文档,他们提到了许多固定对象的方法,但实际上并没有任何补救措施。
然后我查看了源代码,找到了函数 ray.internal.internal_api.free
和 ray.internal.internal_api.global_gc
并尝试了它们,但它们都不起作用
解决方法
PINNED_IN_MEMORY
表示在某处,代码持有一个指向共享内存的指针。可能发生这种情况的一种常见情况是,当对象的值是一个 numpy 数组时,该数组以零个副本进行访问。所以最有可能的问题是这一行:
chromosomes,evaluation,updates_pgScanCaseRate,cache = zip(*ray.get([result for result in results])) # this is line 511 from the above output
虽然这些变量稍后会被 del
删除,但很可能是其他变量(可能是返回值 offspring
?)持有对其中一个的引用。进行复制可能无济于事,因为它不是深度复制(复制对象指针而不是共享内存中的值)。
您可以通过对 ray.get
返回的值进行深拷贝来释放对象存储内存。但如果您不需要其他对象的额外对象存储内存,我也会考虑保留您当前的代码;复制值会增加额外的开销