Erlang内存占用查询
Erlang VM大多数检测内存的工具都是通过erlang:memory()来实现的。
1> erlang:memory().
[{total,13772400},
{processes,4390232},
{processes_used,4390112},
{system,9382168},
{atom,194289},
{atom_used,173419},
{binary,979264},
{code,4026603},
{ets,305920}]
首先,所有的返回值都是字节(bytes)为单位的,它们表示目前被分配的内存(Erlang VM实际使用的内存,不是操作系统给Erlang VM分配的内存),所以这个值要比操作系统分配的小很多。
total:当前分配给进程 processes 和系统 system 的内存总量
processes:当前分配给 Erlang 进程的内存总量
processes_used:当前已被 Erlang 进程使用的内存总量(进程内存的一部分)
system:当前分配给 Erlang 虚拟机,不过没有被 Erlang 进程占用的内存总量。
atom:当前分配给原子的内存总量(系统进程的一部分)
atom_used:当前已被 原子使用的内存总量(系统进程的一部分)
binary:当前分配给二进制数据的内存总量(系统进程的一部分)
code:当前代码数据所占用的内存总量(系统进程的一部分)
ets:当前分配给 ETS 表的内存总量(系统进程的一部分)
查看进程数目是否正常,是否超过了erlang虚拟机的最大进程数。
1> erlang:system_info(process_count).
查看占用内存最高的进程
%% (以输出text方式启动etop,其间隔为1秒,输出行数为20行,按照内存排序. 这里spawn一个新进程,目的是输出etop数据时不影响erlang shell 输入.)
1> spawn(fun()-> etop:start([{output, text}, {interval, 1}, {lines, 20}, {sort, memory}]) end).
手动gc回收内存
1> erlang:garbage_collect(pid(0,12571,0)).
通过erlang:memory()查看节点内存占用总览,需要通过静态和动态两个维度对内存进行考核:
静态: 各类内存占用比例,是否有某种类的内存占用了节点总内存的绝大部分
动态: 各类内存增长特性,如增长速度,或是否长期增长而不回收(atom除外)
atom
atom不会被GC,这意味着我们应该对atom内存增长更加重视而不是忽略。在编写代码时,尽量避免动态生成atom,因为一旦你的输入源不可靠或受到攻击(特别针对网络消息),atom内存增长可能导致节点crash。
ets
ets内存占用通常是由于表过大,通过ets:i().查看ets表条目数,大小,占用内存等。
process
进程内存占用过高可能有两方面原因,进程数量过大和进程占用内存过高。针对于前者,首先找出那些没有被链接或监控的”孤儿进程”。
binary
erlang binary大致上分为两种,heap binary(<=64字节)和refc binary(>64字节),分别位于进程堆和全局堆上,进程通过ProBin持有refc binary的引用,当refc binary引用计数为0时,被GC。
Erlang虚拟机内存布局
Erlang 自己实现的内存分配器, 并非操作系统的内存分配器, Erlang 需要调用操作系统的分配器获取一大块内存, 并用于 Erlang 系统内部的内存分配, 来满足比如创建进程, 原子, 二进制数据, 驱动等数据结构的内存需求。Erlang过程的内存布局的三个重要的点:进程控制模块,栈和堆。它和Unix的内存布局非常的相像。
进程控制模块:进程控制模块会保存一些关于进程的信息比如它在进程表中的标识符(PID)、当前状态(运行、等待)、它的注册名、初始和当前调用,同时PCB也会保存一些指向传入消息的指针,这些传入消息是存储在堆中连接表中的。
栈:它是一个向下生长的存储区,这个存储区保存输入和输出参数、返回地址、本地变量和用于evaluating expressions的临时空间。
堆:它是一个向上生长的存储区,这个存储区保存进程邮箱的物理消息,像列表、元组和Binaries这种的复合项以及比像浮点数这种一个机器字更大的对象。超过64机器字的二进制项不会存储在进程私有堆里。他们被称作Refc Binary (Reference Counted Binary)并被存储在一个大的共享堆里,只要有那个Refc Binary指针的进程都可以访问这个堆。这个储存在进程私有堆中的指针叫作ProcBin。
为了结实当前默认Erlang的GC机制,简单的说,它是一个分代复制的垃圾回收,独立运行在每个Erlang进程私有堆的内部,而且它也是发生在全球共享堆中的引用计数垃圾回收。
参考
http://erldoc.com/mod/erlang/memory_0.html?search=erlang:&i=156
https://segmentfault.com/a/1190000005064830
https://segmentfault.com/a/1190000003758525
http://wudaijun.com/2015/12/erlang-datastructures/
http://wudaijun.com/2016/12/erlang-memory-debug/