为什么gc()不能释放内存?

时间:2013-01-29 10:03:48

标签: r garbage-collection

我使用 64 GB RAM Windows 64位计算机上运行模拟。内存使用达到 55%,完成模拟运行后,我会删除rm(list=ls())后工作区中的所有对象,然后是double gc()

我认为这会为下次模拟运行释放足够的内存,但实际内存使用量仅下降1%。咨询了很多不同的论坛,我找不到令人满意的解释,只有模糊的评论如:

  

“根据您的操作系统,释放的内存可能不会返回到操作系统,而是保留在进程空间中。”

我想找到以下信息:

  • 1)哪个操作系统和哪些条件释放内存不会返回到操作系统,
  • 2)是否有任何其他补救措施,而不是关闭R并再次启动它以进行下一次模拟运行?

2 个答案:

答案 0 :(得分:29)

R垃圾收集器在以下(不是那么)微妙的方式中是不完美的:它移动对象(即,它不是 compact 内存)因为它与C库的交互方式。 (某些other语言/实现也受此影响,但others尽管还必须与C进行互动,却设法compacting generational GC < / em>遭受这个问题)。

这意味着如果您轮流分配小块内存然后被丢弃而更大的块用于更永久的对象(这是执行字符串/正则表达式处理时的常见情况),那么您的内存将变为fragmented并且垃圾收集器无能为力:内存被释放,但由于空闲块太短,无法重用。

解决问题的唯一方法是保存所需的对象,重新启动R并重新加载对象。

由于您正在执行rm(list=ls()),即您不需要任何对象,因此您无需保存和重新加载任何内容,因此,在您的情况下,解决方案正是您要避免的 - 重新启动{ {1}}。

PS。垃圾收集是一个非常重要的主题。例如,Ruby used 5 (!) different GC algorithms over 20 years。 Java GC并不糟糕,因为Sun / OracleIBM在各自的GC实现上花费了很多程序员年数。另一方面,R和Python有糟糕的GC - 因为没有人费心去投入必要的人年 - 而且它们很受欢迎。这对你来说是worse-is-better

PPS。相关:R: running out of memory using `strsplit`

答案 1 :(得分:23)

如何检查内存使用情况?通常,虚拟机会分配一些用于存储其数据的内存块。部分分配可能未使用并标记为免费。 GC做的是发现未从其他任何地方引用的数据并将相应的内存块标记为未使用,这并不意味着该内存被释放到OS。从VM的角度来看,现在有更多的可用内存可用于进一步的计算。

正如其他人所问,您是否遇到过内存错误?如果没有,那就没什么可担心的。

编辑: Thisthis应足以理解内存分配和垃圾收集在R中的工作原理。

从第一份文件:

  

偶尔会尝试将未使用的页面释放回   操作系统。当页面被释放时,会有许多空闲节点   等于R_MaxKeepFrac乘以每个分配节点的数量   课程保留。不需要满足此要求的页面   释放。每个R_PageReleaseFreq级别1都会尝试释放页面   或2级集合。

EDIT2:

要查看已用内存,请尝试运行gc()并将详细设置为TRUE:

gc(verbose=T)

这是一个内存中包含10'000'000个整数数组的结果:

Garbage collection 9 = 1+0+8 (level 2) ... 
10.7 Mbytes of cons cells used (49%)
40.6 Mbytes of vectors used (72%)
          used (Mb) gc trigger (Mb) max used (Mb)
Ncells  198838 10.7     407500 21.8   350000 18.7
Vcells 5311050 40.6    7421749 56.7  5311504 40.6

这是在丢弃对它的引用之后:

Garbage collection 10 = 1+0+9 (level 2) ... 
10.7 Mbytes of cons cells used (49%)
2.4 Mbytes of vectors used (5%)
         used (Mb) gc trigger (Mb) max used (Mb)
Ncells 198821 10.7     407500 21.8   350000 18.7
Vcells 310987  2.4    5937399 45.3  5311504 40.6

正如您所看到的,Vcells使用的内存从40.6Mb降至2.4Mb。