Erlang 内存泄漏分析

随着项目越来越依赖Erlang,碰到的问题也随之增加。前段时间线上系统碰到内存高消耗问题,记录一下troubleshooting的分析过程。线上系统用的是Erlang R16B02版本。

问题描述

有几台线上系统,运行一段时间,内存飙升。系统模型很简单,有网络连接,pool中找新的process进行处理。top命令观察,发现内存都被Erlang进程给吃完了,netstat命令查看网络连接数,才区区几K。问题应该是Erlang内存泄漏了。

分析方法

Erlang系统有个好处,可以直接进入线上系统,在生产现场分析问题。我们系统是通过Rebar管理的,可以用不同方法进入线上系统。

本机登录

可以直接登录到线上机器,然后通过以下命令attach到Erlang系统里面

$ cd /path/to/project
$ rel/xxx/bin/xxx attach
([email protected])>

通过remote shell

获取Erlang系统的cookie

$ ps -ef |grep beam  %%找到参数 --setcookie

新开一个shell,使用同样的cookie,不同的nodename

$ erl --setcookie cookiename -name [email protected]

用start remote shell进入系统

Erlang R16B02 (erts-5.10.3) [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V5.10.3  (abort with ^G)
([email protected])1> net_adm:ping(‘[email protected]‘).
pong
([email protected])2> nodes().
[‘[email protected]‘]
([email protected])3>
User switch command
 --> h
  c [nn]            - connect to job
  i [nn]            - interrupt job
  k [nn]            - kill job
  j                 - list all jobs
  s [shell]         - start local shell
  r [node [shell]]  - start remote shell
  q                 - quit erlang
  ? | h             - this message
 --> r ‘[email protected]‘
 --> j
   1  {shell,start,[init]}
   2* {‘[email protected]‘,shell,start,[]}
 --> c 2

分析流程

Erlang有很多工具,可以分析系统信息,比如appmonwebtool。但是系统内存严重不足,已经没有办法启动这些工具了,幸好还有Erlang shell。

Erlang shell自带了很多有用的命令,可以用help()方法查看

> help().

Erlang系统内存消耗情况

top结果显示,是内存问题,所以第一步可以先看看Erlang的系统内存消耗情况

> erlang:memory().

memory()可以看到Erlang emulator分配的内存,有总的内存,atom消耗的内存,process消耗的内存等等。

Erlang process创建数量

线上系统发现主要内存消耗都在process上面,接下来要分析,是process内存泄漏了,还是process创建数量太多导致。

> erlang:system_info(process_limit).  %%查看系统最多能创建多少process
> erlang:system_info(process_count).  %%当前系统创建了多少process

system_info()返回当前系统的一些信息,比如系统process,port的数量。执行上面命令,大吃一惊,只有2,3k的网络连接,结果Erlang process已经有10多w了。系统process创建了,但是因为代码或者其它原因,堆积没有释放。

查看单个process的信息

既然是因为process因为某种原因堆积了,只能从process里找原因了

先要获取堆积process的pid

> i().  %%返回system信息
> i(0,61,886).  %% (0,61,886)是pid

看到有很多process hang在那里,查看具体pid信息,发现message_queue有几条消息没有被处理。下面就用到强大的erlang:process_info()方法,它可以获取进程相当丰富的信息。

> erlang:process_info(pid(0,61,886), current_stacktrace).
> rp(erlang:process_info(pid(0,61,886), backtrace)).

查看进程的backtrace时,发现下面的信息

0x00007fbd6f18dbf8 Return addr 0x00007fbff201aa00 (gen_event:rpc/2 + 96)
y(0)     #Ref<0.0.2014.142287>
y(1)     infinity
y(2)     {sync_notify,{log,{lager_msg,[], ..........}}
y(3)     <0.61.886>
y(4)     <0.89.0>
y(5)     []

process在处理Erlang第三方的日志库lager时,hang住了。

问题原因

查看lager的文档,发现以下信息

Prior to lager 2.0, the gen_event at the core of lager operated purely in synchronous mode. Asynchronous mode is faster, but has no protection against message queue overload. In lager 2.0, the gen_event takes a hybrid approach. it polls its own mailbox size and toggles the messaging between synchronous and asynchronous depending on mailbox size.

{async_threshold, 20}, {async_threshold_window, 5}

This will use async messaging until the mailbox exceeds 20 messages, at which point synchronous messaging will be used, and switch back to asynchronous, when size reduces to 20 - 5 = 15.

If you wish to disable this behaviour, simply set it to ‘undefined‘. It defaults to a low number to prevent the mailbox growing rapidly beyond the limit and causing problems. In general, lager should process messages as fast as they come in, so getting 20 behind should be relatively exceptional anyway.

原来lager有个配置项,配置message未处理的数量,如果message堆积数超出,则会用 同步 方式处理!

当前系统打开了debug log,洪水般的log把系统给冲垮了。

老外也碰到类似问题,这个thread给我们的分析带来很多帮助,感谢一下。

总结

Erlang提供了丰富的工具,可以在线进入系统,现场分析问题,这个非常有助于高效、快速的定位问题。同时,强大的Erlang OTP让系统有更稳定的保证。我们还会继续挖掘Erlang,期待有更多的实践分享。

关于作者

微博@liaolinbo,云巴首席工程师。曾于Oracle工作。

时间: 2024-10-18 00:02:46

Erlang 内存泄漏分析的相关文章

View的post方法导致的内存泄漏分析

简述: 写这篇文章的缘由是最近项目中查内存泄漏时,发现最终原因是由于异步线程调用View的的post方法导致的. 为何我会使用异步线程调用View的post方法,是因为项目中需要用到很多复杂的自定义布局,需要提前解析进入内存,防止在主线程解析导致卡顿,具体的实现方法是在Application启动的时候,使用异步线程解析这些布局,等需要使用的时候直接从内存中拿来用. 造成内存泄漏的原因,需要先分析View的post方法执行流程,也就是文章前半部分的内容 文章内容: View#post方法作用以及实

android 内存泄漏分析技巧

java虚拟机运行一般都有一个内存界限,超过这个界限,就会报outofmemory.这个时候一般都是存在内存泄漏.解决内存泄漏问题,窃以为分为两个步骤:分析应用程序是否真的有内存泄漏,找到内存泄漏的地方.这两个步骤都不是一般意义上的调试,直接打log,断点调试都不是太给力.动脑筋想一想,内存问题应该在很多地方上都会出现,这么常见的问题应该是有工具的.android现在更可以说是一个生态系统,当然也有很多开发辅助工具.在前面的两个步骤中都有很强大的武器,熟练的掌握这些利器,分析问题就会事半功倍.

使用Eclipse Memory Analyzer进行内存泄漏分析三部曲

源地址:http://seanhe.iteye.com/blog/898277 一.准备工作 分析较大的dump文件(根据我自己的经验2G以上的dump文件就需要使用以下介绍的方法,不然mat会出现oom)需要调整虚拟机参数 找个64位的系统在MemoryAnalyzer.ini设置-Xmx2g 如果是32位的xp可以使用下面的方法进行尝试: 安装jrockit 6.0的JDK mat使用jrockit的jdk来启动 Java代码   -vm D:/Program Files/Java/jroc

Java内存泄漏分析与解决方案

Java内存泄漏是每个Java程序员都会遇到的问题,程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪,那么如何最快最好的检测程序的稳定性,防止系统崩盘,作者用自已的亲身经历与各位网友分享解决这些问题的办法. 作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端.服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存和CPU资源消耗急剧增加,持续增长到出现java.lang.Ou

100%正确的内存泄漏分析工具 &#160; &#160; &nbsp; --------tMemMonitor (TMM)

C/C++由于灵活.高效的优点一直以来都是主流的程序设计语言之一,但是其内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放不再使用的内存时就会造成内存泄漏.在大型.复杂的应用程序中,内存泄漏往往是最常见的问题,因而及时解决内存泄漏非常必要.tMemMonitor (TMM)作为一个专业.准确.易用的内存泄漏分析工具,可以帮助C/C++程序员迅速地解决内存泄漏这个令人头疼的问题. TMM下载地址: 一.开发背景 目前市面上已有一些Windows平台下的内存泄漏动态检测工具,比如U

Android内存泄漏分析实战

内存泄漏简单介绍 java能够保证当没有引用指向对象的时候,对象会被垃圾回收器回收.与c语言自己申请的内存自己释放相比,java程序猿轻松了非常多.可是并不代表java程序猿不用操心内存泄漏.当java程序发生内存泄漏的时候往往具有隐蔽性.因此要借助一些专业的平台资源去保证安全性,比如能够通过加密实现. 定义 引用百度百科的定义:"用动态存储分配函数动态开辟的空间,在使用完成后未释放,结果导致一直占领该内存单元. 直到程序结束".从程序员的角度来看"内存泄漏",事实

Node.js内存泄漏分析

在极客教育出版了一个视频是关于<Node.js 内存泄漏分析>,本文章主要是从内容上介绍如何来处理Node.js内存异常问题.如果希望学习可前往极客学院: 本文章的关键词 - 内存泄漏 - 内存泄漏检测 - GC分析 - memwatch 文章概要 由于内存泄漏在Node.js中非常的常见,可能在浏览器中应用javascript时,对于其内存泄漏不是特别敏感,但作为服务器语言运行时,你就不得不去考虑这些问题.由于很小的逻辑可能导致服务器运行一天或者一个星期甚至一个月才会让你发现内存不断上涨,而

内存泄漏分析工具tMemMonitor (TMM)使用简介

C/C++由于灵活.高效的优点一直以来都是主流的程序设计语言之一,但是其内存的分配与释放均由程序员自己管理,当由于疏忽或错误造成程序未能释放不再使用的内存时就会造成内存泄漏.在大型.复杂的应用程序中,内存泄漏往往是最常见的问题,因而及时解决内存泄漏非常必要.tMemMonitor (TMM)作为一个专业.准确.易用的内存泄漏分析工具,可以帮助C/C++程序员迅速地解决内存泄漏这个令人头疼的问题. TMM下载地址:http://download.csdn.net/download/tmemmoni

Android内存泄漏分析及调试

尊重原创作者,转载请注明出处: http://blog.csdn.net/gemmem/article/details/13017999 此文承接我的另一篇文章:Android进程的内存管理分析 首先了解一下dalvik的Garbage Collection: 如上图所示,GC会选择一些它了解还存活的对象作为内存遍历的根节点(GC Roots),比方说thread stack中的变量,JNI中的全局变量,zygote中的对象(class loader加载)等,然后开始对heap进行遍历.到最后,