我自己写的文章居然被别人的博客转载了,然后大言不惭的说作者是他,真是服了。。。
==============================
今天来说一下长期运行的项目会有内存越用越大的情况的发生原因。中所周知,erlang是运行在虚拟机上的,他的GC不是全局的而是针对进程单独GC。所以GC时整个系统不会产生中断,这是他的优点。那么既然有GC为什么还会有内存的增长呢??
当我们运行这个命令(erlang:memory())会发现,内存的增长主要是在binary上。要找到这个原因,就要知道GC里关于binary的处理。
在erlang中,binary的存储位置一共有两处:
1.size<=64 bytes的binary存储在每个进程单独的heap(堆)中。这种bianry叫做Heap-binary。
2.size>64 bytes的binary存储在虚拟机分配出来单独的heap(堆)中,而用到这个binary的进程的heap中只有一个这个binary的引用。这种binary叫做Refc-binaries。
在进程进行GC的时候Heap-binary会随着GC而被释放掉,因为他是只属于这个进程的。相对应的这个进程heap中存储的Refc-binary也会被释放掉,但是其引用的元binary不会被释放,除非所有引用过这个Refc-binary的进程都进行GC后才会被释放。
这里说一下为什么Refc-binaries叫这个名字呢?这个名字全称是Reference-counted-binary,每当有个进程用到这个binary时,除了在自己进程heap中创建这个binary的引用以外,还要把记录这个binary的引用次数+1。只有当这个binary的引用次数为0的时候,才会把这个binary从专门的heap中释放掉。
在我们写erlang代码的时候,很容易遇到这种情况,<<A:8, B:16>> = C.在这里C本身是一个binary,A和B是C的sub-binary,在这个匹配语句中,erlang的VM不会创建2个新的binary,而是对C创建两个引用。这种引用叫做sub-binary。所以在VM中一共有4中binary,分别是:Heap-binary,Heap-binary的sub-binary,Refc-binary,Refc-binary的sub-binary。
而不论是Refc-binary还是Refc-binary的sub-binary,这两种binary都适用刚才说的Refc的GC规则,所以才会导致erlang项目在长期运行后,内存会出现越用越大的情况。具体原因可以举个例子,如果系统中的某个erlang进程起到类似路由的功能,很多Refc-binary的传递都要到这个进程中中转,结果其实这个进程不会操作这些Refc-binary,而由于这个进程基本什么都不干,仅仅中转一下消息所以基本不会有GC的机会,导致了系统中的大量Refc-binary无法得到释放,所以系统内存binary会越用越大。
针对这种情况怎么解决呢?
在创建这些“关键”进程的时候,在选项中加入{fullsweep_after, 0},这个选项的意思是如果有没用的binary,会立马释放掉。
经过了一段时间的研究,发现上面红色字的部分完全说错了,但是我不打算改,而是标注出来,这样可以提醒我自己和大家,以后不太懂的时候别出来装逼了,被发现了就惨了。
下面来说说研究结果:
关于binary的GC有两种:
1.Heap的GC是分代GC。
所谓分代是指数据存储分为young和old两代,最开始所有的Heap-binary都存储在young heap区域,然后当这个young heap空间不足的时候,VM就会对这个进程进行一次浅扫描(minor collection),给当前所有young heap里面的binary的扫描次数+1, 然后把还有用的binary移到新创建的young heap里,把扫描次数大于1的binary放到old heap中,然后删除原有的young heap。为什么这么做呢?因为根据统计学的说法,大部分数据的生存周期都比较短,最新的数据更容易不再被使用。
当old heap空间不足的时候,VM就会对这个进程进行深扫描(major collection),把young&old heap的所有有用的数据放入新的young heap中,然后删除原来的young&old heap。
2.Refc的GC是引用计数的GC。
引用计数的GC上面已经说了,每个用到这个binary的进程都会把这个binary的引用存储在进程自己的Heap空间中,这个引用被叫做ProcBin,然后会给ProcBin在公共Heap里面的Object的计数器+1,进程GC的时候,只要永不到对应的ProcBin就会被GC掉,然后对应的公共Heap里面的Object的计数器-1,当计数器变为0的时候,这个binary被从公共Heap中释放掉。
而{fullsweep_after, Integer}起作用的是对进程自己的Heap binary起作用,Integer的作用是表示,执行Integer次浅扫描后,直接执行深扫描,不用等待old heap满了。
那么这个东西能解决公共Heap区域内存溢出的问题么?
我们假设一个导致内存溢出的情景,还是上面说的那个场景:
如果系统中的某个erlang进程起到类似路由的功能,很多Refc-binary的传递都要到这个进程中中转,结果其实这个进程不会操作这些Refc-binary,而由于这个进程基本什么都不干,仅仅中转一下消息所以基本不会产生新的Heap binary,那么他的私有Heap里面存储的全是ProcBin,结果就是old heap区域怎么也不会满,而VM默认的fullsweep_after是65535,那么假如在65535次浅GC执行完之前很多的Refc-binary把公共Heap区域沾满了,导致没有新的内存可以分配,结果VM由于再接收新的Refc-binary后,没有内存可分配只能挂掉了,这就是传说中的内存泄漏。如果我们给这个路由进程的启动参数设置为{fullsweep_after, 5},也就是5次浅GC后,来一次深GC,那么该进程Heap区域中无用的ProcBin会大幅减少,然后公共Heap区域的内存就会有增有减,保证了整个VM能持续运行。问题解决了! :)
相关推荐
- **高效数据结构**:Erlang内置了几种高效的数据类型如原子(Atom)、二进制(Binary)、列表(List)和元组(Tuple)。 - **垃圾收集**:ERTS采用了标记-清除算法,并支持分代垃圾回收策略。 - **软实时系统**:ERTS支持软...
Erlang的内存泄漏通常是指内存使用随时间不断增加,但相应的垃圾回收(GC)却没有释放这部分内存。Erlang虚拟机(BEAM)在运行时会监控内存的使用情况。如果发现内存使用不断上升,那么很有可能出现了内存泄漏。 ...
少儿编程scratch项目源代码文件案例素材-直升机飞行.zip
wanjunshe_Python-Tensorflow_12888_1745868924470
健康监测_Android开发_BLE蓝牙通信_心率数据采集与存储_基于小米手环2的实时心率监测应用_支持后台长时间运行的心率记录工具_可导出SQLite数据库的心率数据分析系统_适
少儿编程scratch项目源代码文件案例素材-种花模拟器.zip
嵌入式系统开发_FreeRTOS实时操作系统_STM32F103C8T6微控制器_OLED显示屏_DHT11温湿度传感器_多任务调度_多级菜单设计_万年历算法_电子闹钟功能_参数配
基于python实现的粒子群的VRP(车辆配送路径规划)问题建模求解+源码+项目文档+算法解析,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。
scratch少儿编程逻辑思维游戏源码-猫猫粉碎.zip
scratch少儿编程逻辑思维游戏源码-蓝胡子.zip
scratch少儿编程逻辑思维游戏源码-美食大亨.zip
scratch少儿编程逻辑思维游戏源码-洛克人.zip
scratch少儿编程逻辑思维游戏源码-龙冲刺.zip
思幻个人引导页V2.2版本11月29日更新.zip
scratch少儿编程逻辑思维游戏源码-骑士风斩法.zip
移动应用开发_H5CSS3ionicng-cordovaMVVM模式_基于HTML5和CSS3技术实现多页面布局ionic指令数据绑定ui-route单页跳转调用手机
少儿编程scratch项目源代码文件案例素材-植物大战僵尸创造版 Ver. 1.0.3.zip
scratch少儿编程逻辑思维游戏源码-日落(2).zip
动态星空背景个人主页(带后台).zip
scratch少儿编程逻辑思维游戏源码-迷雾森林:诞生 3.2 起源觉醒.zip