🚀 AI 一键生成 joinquant 策略代码
立即体验

聚宽 JoinQuant 回测内存超限被终止?教你如何使用 disable_cache 与内存优化技巧

joinquant | 发布时间: 2026/7/22
以下内容由 EasyQuant 生成。

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: joinquant 回测提速与内存优化:disable_cache 的使用场景

Question: 回测因为内存超限(超过3G)被系统终止,如何在聚宽中优化内存并使用 disable_cache?

解决方案

在聚宽(JoinQuant)平台进行高频、多因子或长周期回测时,策略经常会因为内存占用超过系统上限(通常为 3G)而被系统强制终止(报错提示内存超限)。为了解决这一痛点,聚宽提供了 disable_cache() 接口,并支持一系列内存管理机制。

一、 什么是 disable_cache()

在默认情况下,聚宽的回测引擎会启用缓存机制(Cache)来暂存历史行情数据、财务数据等,以极大地加快二次数据获取的速度。然而,当您的策略需要处理大量股票(如全市场选股)或获取极长周期的分钟/Tick级数据时,缓存的数据量会呈指数级增长,最终撑爆 3G 的内存限制。

调用 disable_cache() 可以关闭平台的缓存机制。关闭后,系统不再在内存中常驻历史数据,从而大幅降低内存占用,避免回测因内存超限而中断。

注意: 关闭缓存后,由于每次获取数据都需要重新从底层读取,策略的运行速度会有明显下降。因此,这是一种“空间换时间”的折中方案。


二、 如何在代码中使用 disable_cache

disable_cache() 必须在策略的初始化函数 initialize(context) 中调用。以下是一个标准的初始化配置示例:

# 导入聚宽函数库
import jqdata

def initialize(context):
    # 1. 开启真实价格模式(推荐)
    set_option('use_real_price', True)
    
    # 2. 当策略内存占用过大时,调用此函数关闭缓存机制以防止内存超限被杀
    disable_cache()
    
    # 3. 设定基准
    set_benchmark('000300.XSHG')
    
    # 4. 注册每日运行函数
    run_daily(market_open, time='every_bar')

def market_open(context):
    # 策略逻辑代码
    pass

三、 配合 disable_cache 的多维度内存优化方案

除了简单地关闭缓存,您还可以通过优化 Python 代码结构来进一步控制内存占用:

1. 避免跨日期缓存大型数据对象

不要将 historyattribute_historyget_price 返回的大型 DataFrame 赋值给全局变量 g。这些数据应该在每次函数运行结束时被垃圾回收。

2. 善用 df=False 参数

在调用 historyattribute_history 时,默认返回的是 pandas.DataFrame。DataFrame 的构建和维护非常消耗内存和 CPU。如果不需要复杂的 pandas 操作,建议设置 df=False,让 API 返回轻量级的 numpy.ndarraydict

# 推荐:使用 df=False 降低内存消耗
h = history(5, unit='1d', field='close', security_list=['000001.XSHE'], df=False)
close_mean = h['000001.XSHE'].mean()

3. 限制 get_fundamentals 的单次查询量

聚宽对财务数据查询有单次 5000 条的限制。频繁或一次性查询过多股票的财务数据会瞬间拉高内存。建议分批次查询,或者仅筛选出核心股票池后再进行财务数据检索。

4. 显式调用 Python 垃圾回收(GC)

在策略的 after_trading_end(收盘后)或大循环结束时,显式释放内存:

import gc

def after_trading_end(context):
    # 显式进行垃圾回收,释放临时变量占用的内存
    gc.collect()

5. 避免在 g 对象中存储无法序列化的对象

模拟盘和回测在保存状态时会使用 pickle 序列化 g 对象。如果 g 中包含数据库连接、打开的文件句柄或未关闭的网络请求,不仅会导致保存失败,还会造成内存泄漏。对于此类对象,应在 process_initialize 中初始化,并以双下划线 __ 开头命名(系统会自动忽略序列化)。