一、内存溢出的问题

1、堆内存溢出

  (1)压测执行一段时间后,系统处理能力下降。这时用JConsole、JVisualVM等工具连上服务器查看GC情况,每次GC回收都不彻底并且可用堆内存越来越少(证明已经出现了内存泄漏的现象,继续2)。

  (2)压测持续下去,最终在日志中有报错信息:java.lang.OutOfMemoryError.Java heap space。

        定位方法:

  (1)使用jmap -histo 进程id > test.txt  命令将堆内存使用情况保存到test.txt文件中,打开文件查看排在前20的类名中有没有自己公司项目的类名,如果有则基本可以定位堆内存溢出是这个类导致的。

  (2)如果没有,则使用命令:jmap -dump:live,format=b,file=test.dump 进程id生成test.dump文件,然后使用MAT工具进行堆内存分析。

2、持久代溢出

       (1)压测执行一段时间后,日志中报错:java.lang.OutOfMemoryError: PermGen space(这个报错是持久代溢出的标识)。

        产生原因:

        由于类、方法描述、字段描述、常量池、访问修饰符等一些静态变量太多,将持久代空间占满导致溢出。

        解决方法:

        修改JVM参数,将XX:MaxPermSize参数调大既可以解决,建议代码中尽量减少静态变量。

3、栈内存溢出

       (1)压测执行一段时间后,日志中报错:java.lang.StackOverflowError(这个报错是栈内存溢出的标识

        产生原因:

        一般是递归没返回,批量操作数据,循环调用等造成。

        解决方法:

        修改JVM参数,将Xss参数改大,增加栈内存

4、系统内存溢出

      (1)压测执行一段时间后,日志中出现报错:java.lang.OutOfMemoryError: unable to create new native thread。

       产生原因:

       操作系统没有足够的系统资源造成的,系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。所以,当线程数量达到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就会出现这个报错

       解决方法:

  a:减少堆内存

  b:减少线程数量

  c:修改-Xss参数减小单个线程大小,通过生成更多的线程来解决

5、JAVA直接内存溢出

      (1)压测执行一段时间后,日志中出现报错:OutOfMemoryError

       产生原因:

  a:当直接内存达到最大限制时就会触发GC,如果回收失败则会引起OutOfMemoryError。

  b:直接内存在读和写的性能都高于堆内内存,但是内存申请速度却低于堆内内存。

       解决方法:

       在需要频繁申请的场景下不应该使用直接内存(DirectMemory),而应该使用堆内内存(HeapMemory)。

 

5、内存泄漏现象

     (1)如果怀疑是内存泄漏,可以使用JProfiler等工具连上服务器后再开始压测,运行一段时间后点击“Mark Current Values”,后续的运行就会显示增量,这时手动执行一下GC,观察哪个类没有彻底回收,基本就可以判断是这个类导致的内存泄漏现象。

     (2)可以通过命令:jstat -gcutil 进程id  间隔时间(毫秒) 来分析垃圾回收的次数及每次回收的时间,如图:

             

 

 

      解决方式:

      需要优化代码,例如当对象使用完毕后置成null等。

 

二、CPU占用率过高

1、用户 cpu高

       (1)压测过程中,使用top命令查看系统资源占用情况,us cpu过高,例如超过70%以上。

        定位方法:

  (1)通过top命令找出CPU最高的进程

  (2)通过命令  top -H -p 进程号 依次找出进程中占用cpu最高的线程

  (3)通过命令 printf "%x\n"  依次把线程转换成16进制

  (4)再通过命令 jstack 进程id >test.txt 把整个进程信息输出,进入到文件里面通过3的16进制搜索的相应的线程,查询线程具体情况

2、系统 cpu高

       (1)压测过程中,使用top命令查看系统资源占用情况,sy cpu过高,例如超过70%以上。

        定位方法:

  (1)首先通过命令 iostat等查看磁盘繁忙程度、磁盘的队列情况

  (2)如果磁盘没有问题,再使用strace命令查看系统内核调用情况

 

三、线程死锁

  (1)压测一段时间后,程序停顿,报超时错误。(这种现象并不一定是线程死锁造成的,也可能是数据库连接池被占满、数据库死锁造成的)

  (2)获取不到数据

        定位方法:

  (1)通过命令:jstack -l 进程号 查看Java进程下所有线程的情况

  (2)如果有Blocked状态的线程,说明线程死锁,如果大量线程都是Waiting状态,则需要去查询数据库连接池的信息,可能会有排队情况。

  (3)使用JConsole,JVisualVM,JProfiler等工具直接查看所有线程的情况

 

posted on 2020-04-07 16:10  wfw001  阅读(503)  评论(1编辑  收藏  举报