• 性能问题分析-OOM内存溢出


    1. 堆内存溢出
      内存溢出主要存在问题就是出现在这个情况中。当在JVM中如果98%的时间是用于GC且可用的 Heap size 不足2%的时候将抛出此异常信息。

    现象:

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

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

    排查手段:

      (1)使用jmap -histo pid > test.txt命令将堆内存使用情况保存到test.txt文件中,打开文件查看排在前50的类中有没有熟悉的或者是公司标注的类名,如果有则高度怀疑内存泄漏是这个类导致的。

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

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

    解决方式:优化代码,对象使用完毕,需要置成null

     
    jamp分析堆内存溢出
    命令介绍:获取java进程 heap 分配快照,对象统计信息, dump 堆到hprof 二进制文件,供其他工具分析
    jmap -heap  pid
    jmap -histo pid 
    jmap -histo pid > 1.txt
    jmap -histo pid | less
    jmap -dump :live,format=b,file=test.bin pid (生成一个test.bin的文件)
    jhat test.bin 或者 jhat -J-mx800m test.bin启动一个java服务,用浏览器进行访问分析
    
    • jmap -heap pid

    • jmap -histo pid > 3.txt 最简单快速定位内存溢出,前20个基本能找出来

    • jmap -dump :live,format=b,file=test.bin pid (生成一个test.bin的文件)
     
    • 浏览器输入IP:7000访问,进行分析
     
    • jstat -gcutil 1893 1000 20(监控进程1893,1000毫秒打印一次,打印20次,监视java虚拟机垃圾回收情况,各种gc的统计数据)
     
    S0:存活区1使用占比
    S1:存活区2使用占比
    E:伊甸园区使用占比
    O:老年代使用占比
    P:持久带使用占比
    YGC:YGC的次数
    YGCT:YGC的时间
    FGC:FGC的次数
    FGCT:FGC的时间
    GCT:总GC的时间
    

      

    2. 非堆溢出(永久代/方法溢出)
      
     现象:压测执行一段时间后,日志中有报错信息:java.lang.OutOfMemoryError: PermGen space。

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

    解决方法:修改JVM参数,将XX:MaxPermSize参数调大。尽量减少静态变量。

     
     
    3. 系统内存溢出 

    现象:压测执行一段时间后,日志中有报错信息:java.lang.OutOfMemoryError: unable to create new native thread。(无法创建新的线程

    产生原因:操作系统没有足够的资源来产生返个线程造成的。系统创建线程时,除了要在Java堆中分配内存外,操作系统本身也需要分配资源来创建线程。因此,当线程数量大到一定程度以后,堆中或许还有空间,但是操作系统分配不出资源来了,就出现这个异常了。

    解决方法:

      (1)减少堆内存

      (2)减少线程数量

      (3)如果线程数量不能减少,则减少每个线程的堆栈大小,通过-Xss减小单个线程大小,以便能生产更多的线程。

     
     4.栈内存溢出

    现象:压测执行一段时间后,日志中有报错信息:java.lang.StackOverflowError。

    产生原因:线程请求的栈深度大于虚拟机所允许的最大深度,递归没返回,戒者循环调用造成。

    解决方法:修改JVM参数,将Xss参数改大,增加栈内存。栈内存溢出一定是做批量操作引起的,减少批处理数据量。

     
    5.JAVA直接内存溢出

    现象:压测执行一段时间后,日志中有报错信息:OutOfMemoryError

    产生原因:

      (1)直接内存大多时候也被称为堆外内存,直接内存通过 native 方法可以分配堆外内存,通过 DirectByteBuffer 对象来操作。直接内存不属于 Java 堆,所以它不受堆内存大小限制,但是它受物理内存大小的限制。

      (2)可以通过 -XX:MaxDirectMemorySize 参数来设置最大可用直接内存,如果启动时未设置则默认为最大堆内存大小,即与 -Xmx 相同。即假如最大堆内存为1G,则默认直接内存也为1G,那么 JVM 最大需要的内存大小为2G多一些。当直接内存达到最大限制时就会触发GC,如果回收失败则会引起OutOfMemoryError。

      (3)直接内存在读和写的性能都优于堆内内存,但是内存申请速度却不如堆内内存。

    解决方法:因此直接内存适用于需要大内存空间且频繁访问的场合,不适用于频繁申请释放内存的场合。在需要频繁申请的场景下不应该使用直接内存(DirectMemory),而应该使用堆内内存(HeapMemory)。

  • 相关阅读:
    转:如何判断软件功能特性的依赖
    原创:运行loadtest时报错the load test results repository was created with a previous version and is not compatible
    转:使用正则表达式进行高效的测试
    6.2.1 HTTP音频播放
    6.2 网络音频
    6.1.3 控制服务中的MediaPlayer
    android开源项目和框架
    6.1.2 加上MediaPlayer的本地服务
    6.1.1 服务
    6.1 后台音频播放
  • 原文地址:https://www.cnblogs.com/mululu/p/15079377.html
Copyright © 2020-2023  润新知