美文网首页jvm调优jvm
Linux下Java项目占用内存问题的分析

Linux下Java项目占用内存问题的分析

作者: 烨枫_邱 | 来源:发表于2018-01-20 14:09 被阅读181次

    这两天发现一个问题,即自动化测试平台所在的服务器内存突然就爆了。从现象上看,服务器上执行命令行pandning,日志回吐卡顿,机器卡死......个人感觉这个问题比较蹊跷也很隐蔽,从原则上,讲为了不要眉毛胡子一把抓导致下错定义,故而花了些时间仔细研究了一下。

    “内存一直占满”


    首先,可以通过free 或者 free -b -s2查看一个Linux内存使用情况,如下图:

    内存使用样例图

    当发现内存使用率这个数字一直攀升或者已经达到很大值时,就开始紧张起来了;别着急,接下来咱们先看看资料:

    在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然。这是Linux内存管理的一个优秀特性,在这方 面,区别于 Windows的内存管理。主要特点是,无论物理内存有多大,Linux 都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能。而Windows 是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间。换句话说,每增加一些物理内存,Linux 都将能充分利用起来,发挥了硬件投资带来的好处,而Windows只将其做为摆设,即使增加8GB甚至更大。

    Linux 的这一特性,主要是利用空闲的物理内存,划分出一部份空间,做为 cache 和 buffers ,以此提高数据访问性能。

    Linux 优先使用物理内存,当物理内存还有空闲时,linux是不会施放内存的,即时占用内存的程序已经被关闭了(这部分内存就用来做缓存了)。也就是说,即时你有8G的内存,用过一段时间后,也会被占满。这样做的好处是,启动那些刚开启过的程序、或是读取刚存取过得数据会比较快,对于服务器很有好处。

    你可以用 free 指令查看一下输出,用 used 减去 buffer 和 cache,才是你运行中的程序所占用的空间,举例如下: 

                 total     used      free    shared   buffers    cached

    Mem:   8061672 7442680 618992 192 163748 5833736

    -/+ buffers/cache: 1445196 6616476

    Swap: 8191996 32540 8159456

    7442680 - 163748 - 5833736 = 1445196

    也就是说目前正在被使用的内存只有 1.3 G。不要被 7000多兆(合约7个G)的used吓住了。 

    windows则总是给内存留下一定的空闲空间,即时内存有空闲也会让程序使用一些虚拟内存,这样做的好处是,启动新的程序比较快,直接分给它些空闲内存就可以了,而linux下呢?由于内存经常处于全部被使用的状态,则要先清理出一块内存,再分配给新的程序使用,因此,新程序的启动会慢一些。

    另外,内存是随机访问的,也就是说,无论你的内存占用了多少,数据的存取时间都是相同的,跟硬盘不同。

    判断Java程序对内存的消耗


    1.使用top

    2.ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head

    具体查看%MEM即可

    导致内存溢出的主要原因


    内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。(可以从以下几个方面去思考)

    引起内存溢出的原因有很多种,常见的有以下几种:

    1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;

    2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;

    3.代码中存在死循环或循环产生过多重复的对象实体;

    4.使用的第三方软件中的BUG;

    5.启动参数内存值设定的过小;

    解决办法


    内存溢出的解决方案

          第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)

      第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。

      第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。

    重点排查以下几点:

    1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

    2.检查代码中是否有死循环或递归调用。

    3.检查是否有大循环重复产生新对象实体。 

    4.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中   数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。 

    5.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

    6.做好监控,持续发现内存使用率的攀升(内存查看工具有许多,比较有名的有:Optimizeit Profiler、JProbe Profiler、JinSight和Java1.5的Jconsole等

    手动清理内存


    1.free -m

    2.开始清理 

    echo 1 > /proc/sys/vm/drop_caches

    3.清理后内存使用情况

    free -m

    4.弊端:容易引起数据丢失,慎用!!!

    相关文章

      网友评论

        本文标题:Linux下Java项目占用内存问题的分析

        本文链接:https://www.haomeiwen.com/subject/sdctaxtx.html