跳至主要内容

Spark内存溢出调试笔记

最近在玩 Spark ,它是个基于内存的分布式计算框架,用起来还是挺方便的,而且相当适合需要迭代计算的算法,比如PageRank和机器学习的算法。Spark的社区相当活跃,每天都有很多user提问,每天的commit数也是超过1000的。
以前Spark利用mesos集群或者用自己启动的集群来进行分布式计算。由于国内很多公司只维护了hadoop集群,我没能看到Spark有投入到生产中(要维护多一个mesos集群成本可是很高的)。然而,在0.6的版本中加入了 on Yarn 模块。这使得很多部署了hadoop集群的公司(升级成支持Yarn的hadoop)可以轻易的使用Spark了。

要好好玩Spark还是需要一点时间的,因为现在的版本还是有不少bug和todo的。最近玩的时候还是遇到了个比较让人头大的问题的,当我迭代调用collect方法的时候,会出现一个让人比较头大的问题:

  1. Master无缘无故就跑的很慢
  2. 使得akka超时
  3. Yarn的ResourcesManager告诉我Master用的内存超出预算

出现这个问题之后,我还是真不知道怎么定位原因,现在解决了之后,感觉自己的编程经验还真是太少了。

print GC

首先,我PrintGC的信息,在启动参数中加入下面的参数:

  • -verbose:gc: 输出GC信息
  • -XX:+PrintGCTimeStamps:输出GC时间
  • -XX:+PrintGCDetails:输出GC详细信息,比如新生代GC情况,永久代GC情况,内存的GC汇总等

在这里,我发现Master崩溃前会不断Full GC,并且Full GC后,老年代的内存用量没有降下来,这只可能是用的内存真的需要这么多(给了10G的内存还崩溃真说不过去),或者内存泄露。

dump 内存

这里说的dump就是抽取jvm内存使用状况的快照。启动参数里面还是有不少关于dump的参数的:

  • -XX:-HeapDumpOnOutOfMemoryError:在OOM时,输出一个dump文件,记录当时的内存快照
  • -XX:HeapDumpPath=/tmp/dump.hprof:把dump信息输出到/tmp/dump.hprof中

dump文件的大小通常是jvm占用内存的大小,所以文件可能会很大。

分析dump文件

这是最后的步骤,也是很耗时的步骤了,dump文件是结构化得文件,需要用分析工具才能分析。

  • jhat:dump文件少于1G的时候可以用这个,它会起一个web服务,用于查看dump信息。
  • HeapAnalyzer:直接分析dump并展示的客户端。
  • mat:同样是展示dump的客户端,神器

使用 jhat 和 HeapAnalyzer 都需要有一台内存大于dump文件大小2倍的机器,HeapAnalyzer还需要能显示出来的(桌面操作系统),这下就悲剧了,这样的机器相当难找。
这时可以用强大的mat,mat分析了展示和分析模块,可以用一个脚本先对dump文件分析并产生一堆索引文件(用服务器搞),然后再用mat的桌面应用打开这些文件,4G内存的机器分析8g的dump完全没压力的。 点击这里看教程

最后

用mat找到这个内存泄露的地方了,提个issue,然后就fork and pull request去。

评论

此博客中的热门博文

Spark 矩阵相乘实现

矩阵相乘计算的意义十分重要,比如我们做数据分析经常使用到的join操作就可以理解成为矩阵相乘的一个部分,矩阵相乘在很多分布式计算框架都有自己的实现,这些实现也可以根据不同大小的矩阵做不同的优化,比如在MapReduce上就有两种基本的实现: 大矩阵乘小矩阵 我可以把小矩阵放到DistrubutedCache,让每个mapper读取,这就是hive的MapJoin的实现。 两个大矩阵相乘 相乘中两个矩阵都是超大矩阵的话,为了减少MapReduce过程中产生的巨大数据,使用的带宽。都会采用矩阵分块的做法,以下会详细介绍这种实现方法。 Spark介绍 官网介绍 超大矩阵拆分计算方法 单机(单线程)矩阵相乘 假设有矩阵 A , B ,相乘的结果为 C ,那么相乘的伪代码: C = 0 for(i <- 0 to A.lenght) for(k <- 0 to A[i].lenght) if(A[i][k]!=0) for(j <- B[k].lenght) { C[i][j] += A[i][k] * B[k][j] } 单机的计算中,时间复杂度是 O(n^3),如果 n 增长到一定程度的时候,那么计算用时就会非常大,所以下面会说一下并行计算方法。 并行矩阵相乘 在计算的过程中,我们很容易发现每个 A[i][k] * B[k][j] 都可以单独计算,因此我也可以单独计算这些组合,最后做一个累计就可以获得 C 矩阵了,相乘伪代码如下: A = ((row, column), value) => (column, (row, value)) B = ((row, column), value) => (row, (column, value)) Temp = A.join(B) => (k, (rowA, valueA), (columnB, valueB)) => ((rowA, columnB), valueA * valueB) => ((rowC, columnC), valueC) C = Temp.reduceByKey =...

iphone 自动打包脚本

最近做ios开发,经常需要给老大打ipa包,这个虽然在xcode中编译并打包是很简单的事,不过每次都得花几分钟的时间做一些手动的放入Payload并压缩成zip包的操作。比较麻烦的是,在开发过程中,突然就说要一个可以执行的包做测试。那么,思路断了,正在写的代码要注释掉,这样持续下去浪费的时间会很多,所以还是需要写一个打包脚本。 打包具体用到的命令是这些: xcodebuild: 主要用于编译项目 xcrun: 主要用于打ipa包 具体打包流程就是编译,然后打一个发布包,一个ipa包,其实用脚本来说话就好了。另外,我用一个conf.dat来存放target和configuration,这些都在xcode里面指定好了,用xxx:xxx这样的格式来存放,xcodebuild在编译的时候会自动找到对应的配置。 打包脚本如下: #!/bin/sh basePath=`pwd` distDir="target" distDir="${basePath}/${distDir}" rm -rdf "$distDir" mkdir -p "$distDir" baseName="xxx" #.app 的名字 projectDir=$(cd ../mobile/xxx; pwd) # 进入xcode工程目录 cd $projectDir for line in $(cat ${basePath}/conf.dat) do targetName=`echo $line | cut -f1 -d':'` conf=`echo $line | cut -f2 -d':'` releaseDir="${projectDir}/build/${conf}-iphoneos" rm -rdf "$releaseDir" echo "======build ${baseName}.app start..." echo "======clean ${conf}..." xcodebuild clean -configuration "$...

【转】ELO-对弈与排名(有触感的排名)

原文: https://www.cnblogs.com/leoin2012/p/4854442.html ELO介绍 ELO等级分制度 是指由 匈牙利 裔 美国 物理学家 Elo创建的一个衡量各类对弈活动水平的评价方法,是当今对弈水平评估的公认的权威方法。被广泛用于 国际象棋 、 围棋 、 足球 、 篮球 等运动。网络游戏 英雄联盟 、 魔兽世界 内的竞技对战系统也采用此分级制度。 历史 ELO等级分制度是基于 统计学 的一个评估棋手水平的方法。 美国 国际象棋 协会在1960年首先使用这种计分方法。由于它比先前的方法更公平客观,这种方法很快流行开来。1970年国际棋联正式开始使用等级分制度。 Elo模型原先采用 正态分布 。但是实践显明棋手的表现并非呈正态分布,所以现在的等级分计分系统通常使用的是 Logistic distribution 。 计分方法 假设棋手A和B的当前等级分分别为 和 ,则按Logistic distribution A对B的胜率期望值当为 类似B对A的胜率为 假如一位棋手在比赛中的真实得分 (胜=1分,和=0.5分,负=0分)和他的胜率期望值 不同,则他的等级分要作相应的调整。具体的数学公式为 公式中 和 分别为棋手调整前后的等级分。在大师级比赛中 通常为16。 例如,棋手A等级分为1613,与等级分为1573的棋手B战平。若K取32,则A的胜率期望值为 ,约为0.5573,因而A的新等级分为1613 + 32 · (0.5 − 0.5573) = 1611.166 国际象棋中的等级分 国际象棋中,等级分和棋联称号的大致对应为 2500分以上:国际特级大师 2400-2499分:国际大师 2300-2399分:棋联大师