Erlang内存增长

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gohuge/article/details/81868799

问题概述:

在过去一段时间里,我们遇到了这样一个问题,节点内存占用不断上升。

但奇怪的是消息队列并没有堆积,也没有进程内存占用异常的情况,我们可以通过在Erlang Shell中运行垃圾回收的表达([erlang:garbage_collect(Pid) || Pid <- processes()].)回收内存,但它们又是怎么来的呢?

内存增长图

问题分析:

1、我们最初认为是Linux操作文件(https://linux.cn/article-5627-1.html),所产生的文件缓存,当时的确信了有效果,但不是根本原因。

2、我们通过GC能释放,那意味着存在着本身Erlang VM无法GC到的内容,然而产生这个现象有一下两个途径。

1). 做太少的工作来保证分配和垃圾收集;

2). 使用各种数据结构生成大型堆栈或堆(使用大量的refc二进制文件。 使用二进制文件再次填充堆

(即使使用虚 拟堆来计算refc二进制文件的实际大小)可能会花费大量时间,从而在垃圾收集之间产生长时间延迟。)

3、既然进程占用内存正常,那就是共享内存部分存在问题。

相关知识:

1、Private Heap每次GC调度是那部分的内容

每个Erlang进程创建之后都会有自己的PCB,栈,私有堆。所以Erlang GC不会像java占用调度资源。

Each process’ heap is garbage collected independently. Thus when one scheduler is collecting garbage for a process, other schedulers can keep executing other processes.

2、Shared Heap Erlang 虚拟机对待这部分shared memory 的GC,是采取引用计数器的.

In addition, binaries larger than 64 bytes are stored in a common heap shared by all processes. ETS tables are also stored in a common heap.

Erlang的二进制文件有两种主要类型:ProcBins和Refc二进制文件。

这里有介绍(http://erlang.org/doc/efficiency_guide/binaryhandling.html#id63822

最多64个字节的二进制文件直接分配在进程的堆上,并占用它们在那里使用的位置。 大于该值的二进制文件仅在二进制文件的全局堆中分配,并且每个进程在其本地堆中保存本地引用。 这些二进制文件是引用计数的,只有在为所有持有二进制文件的进程对所有引用进行垃圾收集后才会发生释放。

这种情况出现的几率极低,会出现在如下情况:

1、有极少的时间做垃圾回收;

2、使用大量的refc二进制文件。 使用二进制文件再次填充堆(即使使用虚拟堆来计算refc二进制文件的实际大小)可能会花费大量时间,从而在垃圾收集之间产生长时间延迟。

通常,refc二进制文件内存泄漏可以通过几种不同的方式解决:

1、以给定的间隔手动调用垃圾收集(icky);

2、手动跟踪二进制大小并强制GC,这首先破坏了垃圾收集的目的,并且可能比VM的虚拟二进制堆做得更糟;

3、停止使用二进制文件(不可取);

4、或者在适当的时候添加休眠呼叫(可能是最干净的解决方案)。

猜你喜欢

转载自blog.csdn.net/gohuge/article/details/81868799