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

循环使用readRDS读取大量RDS文件时出现内存泄漏问题

R循环读取大量RDS文件内存飙升问题解决

当循环读取大量RDS文件时,内存占用会急剧飙升,即便每次迭代执行gc()也无法有效缓解。以下是复现问题的代码:

library(rnaturalearth)
library(purrr)
library(glue)

world <- ne_countries(scale = "large", returnclass = "sf")

# 生成测试用RDS文件
walk(1:1000, function(i) {
  saveRDS(world, file = glue("cache/{i}.rds"))
}, .progress = TRUE)

# 读取文件时出现内存飙升
walk(1:1000, function(i) {
  world <- readRDS(glue("cache/{i}.rds"))
}, .progress = TRUE)

通过macOS活动监视器和RStudio内存组件监控,循环前后执行gc()的输出如下:

> gc()
          used (Mb) gc trigger  (Mb) limit (Mb) max used (Mb)
Ncells 1075674 57.5    2266002 121.1         NA  1281588 68.5
Vcells 1655548 12.7    8388608  64.0     102400  2572972 19.7
                                                   
> gc()
          used (Mb) gc trigger   (Mb) limit (Mb)   max used   (Mb)
Ncells 1183433 63.3   17322119  925.2         NA   23685502 1265.0
Vcells 2534823 19.4  791702570 6040.3     102400 1137590813 8679.2

问题原因

核心问题出在purrr::walk的执行环境特性:每次迭代中创建的world对象会被保留在walk的调用环境中,不会被自动回收。即便你在迭代函数内覆盖world变量,旧对象的引用依然存在,导致GC无法释放内存。此外,R的垃圾回收是惰性触发的,即便手动调用gc(),如果对象还有未被移除的引用,也无法回收。

解决办法

1. 改用基础R的for循环

基础for循环的变量作用域更简洁,每次迭代后旧的world对象会失去引用,更容易被GC回收:

# 创建cache目录(如果不存在)
if (!dir.exists("cache")) dir.create("cache")

for (i in 1:1000) {
  world <- readRDS(glue("cache/{i}.rds"))
  # 在这里添加对world的处理逻辑
  rm(world) # 主动移除对象引用
  gc(verbose = FALSE) # 可选:主动触发垃圾回收
}

2. 在walk迭代内主动清理对象

在walk的迭代函数中,主动删除对象并触发GC,确保旧对象失去所有引用:

walk(1:1000, function(i) {
  world <- readRDS(glue("cache/{i}.rds"))
  # 处理world...
  rm(world) # 删除当前环境中的对象引用
  gc(verbose = FALSE) # 触发回收
}, .progress = TRUE)

3. 使用local()隔离局部环境

用local()创建独立的局部环境,迭代结束后环境销毁,里面的对象自动失去引用:

walk(1:1000, function(i) {
  local({
    world <- readRDS(glue("cache/{i}.rds"))
    # 处理world...
  }) # 局部环境执行完毕,world被标记为可回收
}, .progress = TRUE)

内容的提问来源于stack exchange,提问作者user3170702

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:37:03