将数百万条记录写入 mnesia table 占用大量内存(RAM),即使删除这些记录也不会回收

Writing millions records to mnesia table takes up a lot of memory(RAM) and not reclaim even these records are deleted

我是 运行 一个 Erlang 应用程序,经常将数百万条记录写入 mnesia table 以制作调度程序。时间到了,记录将被执行并从 table 中删除。 table配置为{type, disk_copies}, {type, ordered_set}。我使用事务操作来写入,使用脏操作来删除记录。

我有一个实验,写入200万条记录,然后全部删除:完成后RAM内存没有被回收。当我开始删除这些记录时,内存会增加两倍。例如,梁内存开始时为75MB,实验后变为410MB。我用erlang:memory()检查了前后的内存,发现内存被process_used and binary吃掉了,但实际上,我没有对二进制进行任何操作。如果我对所有 运行 个进程使用 erlang:garbage_collect(Pid),内存将被回收,剩下 180MB。

如有任何解决此问题的建议,我们将不胜感激。非常感谢。

来自 Elrang OTP 的 Rickard Green 的回答:

以上不代表bug

一个进程不会被垃圾回收,除非它达到一定的限制,例如,它需要分配堆数据并且没有可用的空闲堆。如果一个进程停止执行,无论经过多长时间,它都不会自动进行垃圾收集,除非它达到这些限制之一。不过,可以通过调用 erlang:garbage_collect() 来强制执行垃圾回收。

一个有大量实时数据(并且已经变大)但在垃圾收集时没有实时数据的进程不会立即缩小到其原始大小。相反,它会得到一个相对较大的堆。堆 space 可供进程免费使用,但它是从系统的角度分配的。选择比较大的堆是为了避免不必要的频繁触发垃圾回收。

当您执行时,不仅您的流程会受到影响。其他进程也可能会建立堆以便为您的进程提供服务。

如果您通过 top 或类似方式查看内存消耗,即使您能够将每个进程垃圾收集到其初始大小,也预计内存使用量在执行后会增加。这是由于内存分配器将内存块放入更大的内存块中,在整个内存块空闲之前不能将其删除。或多或少的每一个存在的内存分配系统都会有这个特性。