You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环导出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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 18:01:15