问题描述
我正在运行一个 Erlang 应用程序,该应用程序经常将数百万条记录写入 mnesia 表以制作调度程序。当时间到期时,记录被执行并从表中删除。该表配置为 {type,disk_copies},{type,ordered_set}
。我使用事务操作来写和脏操作来删除记录。
我有一个实验,写了 200 万条记录,然后将它们全部删除:RAM 内存在完成后没有被回收。当我开始删除这些记录时,有一个尖峰使内存增加了两倍。例如,beam memory 开始时为 75MB,实验后变为 410MB。我之前和之后都用过 erlang:memory()
来检查内存,发现内存被 process_used and binary
吃掉了,但实际上,我对二进制没有任何动作。如果我对所有正在运行的进程使用 erlang:garbage_collect(Pid)
,内存会被回收,留下 180MB。
对于解决此问题的任何建议,我们将不胜感激。非常感谢。
解决方法
来自 Elrang OTP 的 Rickard Green 的回答:
以上并不表示存在错误。
一个进程除非达到一定的限制,否则不会被垃圾回收,例如,它需要分配堆数据并且没有可用的空闲堆。如果进程停止执行,无论经过多长时间,它都不会自动进行垃圾回收,除非它达到这些限制之一。不过,可以通过调用 erlang:garbage_collect() 强制进行垃圾回收。
一个拥有大量实时数据(并且因此变得很大)但在垃圾收集时没有实时数据的进程不会立即缩小到其原始大小。相反,它将获得一个相对较大的堆。堆空间可供进程免费使用,但它是从系统的角度分配的。选择相对较大的堆以避免不必要地频繁触发垃圾收集。
执行时不仅您的流程会受到影响。其他进程也可能会建立堆以便为您的进程提供服务。
如果您通过 top 或类似方式查看内存消耗,即使您能够将每个进程垃圾收集到其初始大小,执行后内存使用量也会增加。这是由于内存分配器将内存块放入更大的内存块中,在整个内存块空闲之前这些块不能被删除。现有的每个内存分配系统或多或少都会具有这种特性。