循环导出Holoviews+Bokeh绘图后内存无法释放的求助
解决Holoviews循环导出PNG内存泄漏问题
问题核心
单独调用df_test.hvplot()内存可正常释放,但执行hv.render()后内存持续增长,根源是Bokeh渲染后的对象存在未被正确清理的上下文引用,全局文档(curdoc)的残留状态无法通过常规del或gc.collect()彻底清除。
有效解决方案
方案1:使用Holoviews原生导出方法
Holoviews内置的hv.save()会自动管理渲染上下文,避免手动调用hv.render()带来的内存泄漏:
import numpy as np import pandas as pd import holoviews as hv import hvplot.pandas import gc print(f"holoviews version: {hv.__version__}") print(f"pandas version: {pd.__version__}") directory_name = 'path_testfolder/' export_name = 'test' df_test = pd.DataFrame(np.random.normal(loc=0.5, scale=0.5, size=(80_000_000, 2)), columns=['x', 'y']) for i in range(100): # 创建绘图 p1 = df_test.hvplot(kind="scatter", x="x", y="y", rasterize=True, datashade=True, width=800, height=800) # 用Holoviews原生方法保存PNG file_out_path = f"{directory_name}/{export_name}_{i}.png" hv.save(p1, file_out_path, fmt='png', dpi=96) # 清理引用并触发垃圾回收 del p1 gc.collect()
方案2:手动隔离Bokeh渲染文档
如果必须使用hv.render()+export_png,每次循环创建独立的Bokeh文档,避免共享全局上下文的残留:
import numpy as np import pandas as pd import holoviews as hv import hvplot.pandas from bokeh.io import export_png, curdoc import bokeh import gc print(f"holoviews version: {hv.__version__}") print(f"bokeh version: {bokeh.__version__}") print(f"pandas version: {pd.__version__}") directory_name = 'path_testfolder/' export_name = 'test' df_test = pd.DataFrame(np.random.normal(loc=0.5, scale=0.5, size=(80_000_000, 2)), columns=['x', 'y']) for i in range(100): # 创建独立的Bokeh文档并清空 doc = curdoc() doc.clear() # 在独立文档上下文内渲染绘图 p1 = df_test.hvplot(kind="scatter", x="x", y="y", rasterize=True, datashade=True, width=800, height=800) with doc: p1_bokeh = hv.render(p1) # 导出图片 file_out_path = f"{directory_name}/{export_name}_{i}.png" export_png(p1_bokeh, filename=file_out_path, height=800, width=800) # 强制清理所有相关对象引用 del p1, p1_bokeh, doc gc.collect()
方案3:分块处理超大数据集(可选)
针对8000万行的超大数据集,可分块加载/处理,进一步降低单次循环的内存占用:
# 示例:从文件分块读取数据 chunk_size = 10_000_000 for chunk_idx, chunk in enumerate(pd.read_csv('your_large_data.csv', chunksize=chunk_size)): p1 = chunk.hvplot(kind="scatter", x="x", y="y", rasterize=True, datashade=True, width=800, height=800) hv.save(p1, f"{directory_name}/{export_name}_chunk_{chunk_idx}.png", fmt='png') del p1 gc.collect()
关键注意事项
- 避免调用
bokeh.io.state.State().reset()这类全局状态重置方法,易导致上下文混乱,改用独立文档或原生导出更可靠。 gc.collect()需在所有目标对象被del后执行,确保垃圾回收能识别无引用对象。- 优先升级Holoviews和Bokeh到最新稳定版,旧版本存在已知的内存泄漏bug。
内容的提问来源于stack exchange,提问作者Debroize
相关产品推荐
相关产品推荐

