上周现网一个内存溢出问题导致应用服务器每隔一小时死一次,遂整理下常见的OMM、发现方法和处理方式,加入Bug预防。

常见的OutOfMemoryError有三种:OutOfMemoryError:PermGen space、OutOfMemoryError:Java heap space、OutOfMemoryError:unable to create new native thread

1. OutOfMemoryError:PermGen space

原因:程序中使用了大量的jar或class,使java虚拟机装载类的空间不够,与Permanent Generation space有关。

处理:

一:增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。

JAVA_OPTS="-XX:PermSize=64M -XX:MaxPermSize=128m"

二: 清理应用程序中WEB-INF/lib下的jar,用不上的jar删除掉,多个应用公共的jar移动到Tomcat的lib目录,减少重复加载。

常用方法:

kill -3 PID

Heap

PSYoungGen total 17024K, used 10442K [0x00007f9e67560000, 0x00007f9e69000000, 0x00007f9e69000000)

eden space 9088K, 27% used [0x00007f9e67560000,0x00007f9e677d6410,0x00007f9e67e40000)

from space 7936K, 99% used [0x00007f9e68840000,0x00007f9e68ffc7b0,0x00007f9e69000000)

to space 9088K, 0% used [0x00007f9e67e40000,0x00007f9e67e40000,0x00007f9e68720000)

PSOldGen total 54656K, used 45409K [0x00007f9e64000000, 0x00007f9e67560000, 0x00007f9e67560000)

object space 54656K, 83% used [0x00007f9e64000000,0x00007f9e66c58620,0x00007f9e67560000)

PSPermGen total 59968K, used 58914K [0x00007f9e5ec00000, 0x00007f9e62690000, 0x00007f9e64000000)

object space 59968K, 98% used [0x00007f9e5ec00000,0x00007f9e62588ac8,0x00007f9e62690000)

PSPermGen-使用率已达到98%,需要加到PermSize

jmap -head PID

[root@chances bin]# ./jmap -heap 12379

Attaching to process ID 12379, please wait...

Debugger attached successfully.

Server compiler detected.

JVM version is 17.0-b16

using thread-local object allocation.

Parallel GC with 6 thread(s)

Heap Configuration:

MinHeapFreeRatio = 40

MaxHeapFreeRatio = 70

MaxHeapSize = 83886080 (80.0MB)

NewSize = 1310720 (1.25MB)

MaxNewSize = 17592186044415 MB

OldSize = 5439488 (5.1875MB)

NewRatio = 2

SurvivorRatio = 8

PermSize = 20971520 (20.0MB)

MaxPermSize = 88080384 (84.0MB)

Heap Usage:

PS Young Generation

Eden Space:

capacity = 9306112 (8.875MB)

used = 5375360 (5.1263427734375MB)

free = 3930752 (3.7486572265625MB)

57.761608714788736% used

From Space:

capacity = 9306112 (8.875MB)

used = 3425240 (3.2665634155273438MB)

free = 5880872 (5.608436584472656MB)

36.80634834397007% used

To Space:

capacity = 9306112 (8.875MB)

used = 0 (0.0MB)

free = 9306112 (8.875MB)

0.0% used

PS Old Generation

capacity = 55967744 (53.375MB)

used = 48354640 (46.11457824707031MB)

free = 7613104 (7.2604217529296875MB)

86.39733629427693% used

PS Perm Generation

capacity = 62062592 (59.1875MB)

used = 60243112 (57.452308654785156MB)

free = 1819480 (1.7351913452148438MB)

97.06831451706046% used

**2. OutOfMemoryError: Java heap space **

原因:java虚拟机创建的对象太多,虚拟机分配给堆内存空间已经用满了,与Heap space有关。

处理:

一:检查程序,看是否有死循环或不必要地重复创建大量对象-修改程序或算法。

public class OOM {

public static void main(String[] args) {

Integer sum1=300000;

Integer sum2=400000;

OOM oom = new OOM();

System.out.println("往ArrayList中加入30w内容");

oom.javaHeapSpace(sum1);

oom.memoryTotal();

System.out.println("往ArrayList中加入40w内容");

oom.javaHeapSpace(sum2);

oom.memoryTotal();

}

public void javaHeapSpace(Integer sum){

Random random = new Random();

ArrayList openList = new ArrayList();

for(int i=0;i

String charOrNum = String.valueOf(random.nextInt(10));

openList.add(charOrNum);

}

}

public void memoryTotal(){

Runtime run = Runtime.getRuntime();

long max = run.maxMemory();

long total = run.totalMemory();

long free = run.freeMemory();

long usable = max - total + free;

System.out.println("最大内存 = " + max);

System.out.println("已分配内存 = " + total);

System.out.println("已分配内存中的剩余空间 = " + free);

System.out.println("最大可用内存 = " + usable);

}

}

执行结果:

往ArrayList中加入30w内容

最大内存 = 20447232

已分配内存 = 20447232

已分配内存中的剩余空间 = 4032576

最大可用内存 = 4032576

往ArrayList中加入40w内容

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

at java.util.Arrays.copyOf(Arrays.java:2245)

at java.util.Arrays.copyOf(Arrays.java:2219)

at java.util.ArrayList.grow(ArrayList.java:242)

at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)

at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)

at java.util.ArrayList.add(ArrayList.java:440)

at pers.qingqian.study.seven.OOM.javaHeapSpace(OOM.java:36)

at pers.qingqian.study.seven.OOM.main(OOM.java:26)

从程序执行结果可明显看出往ArrayList中加入30w内容时内存够用,而当往ArrayList加入40w内容时内存就不够了-抛出异常。

二: 增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。

JAVA_OPTS="-Xms256m -Xmx1024m"

常用方法:

步骤一:获取内存的堆信息

jmap -dump:format=b,file=mem.dat pid

步骤二:使用内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

步骤三:看分析图,查找对应问题

内存溢出.jpg点击See stacktrace

http-8087-140

at org.apache.jsp.template.runtime.tp_005fhd_005fppjc.ppdh_005fdetail_jsp._jspService(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V (ppdh_005fdetail_jsp.java:213)

找到ppdh_005fdetail_jsp.java 的213行(jsp文件编译后)找到如下代码:

ArrayList tempEpilist = (ArrayList)pageContext.getAttribute("episodes");

ArrayList epiList = new ArrayList();

int j=0;

for(int i=0;i

EpgEpisode epi = (EpgEpisode)tempEpilist.get(i);

if(epi.getEpisodeIndex() != (j+1)){ #这里会因为数据的原因产生死循环,从而导致epiList一直在加内容。

epiList.add(epi);

i--;

}else{

epiList.add(epi);

}

j++;

}

内存泄露

内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏随着被执行的次数越多-最终会导致内存溢出。

而因程序死循环导致的不断创建对象-只要被执行到就会产生内存溢出。

内存泄漏常见几个情况

一:静态集合类

声明为静态(static)的HashMap、Vector 等集合

通俗来讲A中有B,当前只把B设置为空,A没有设置为空,回收时B无法回收-因被A引用。

二:监听器

监听器被注册后释放对象时没有删除监听器

三:物理连接

DataSource.getConnection()建立链接,必须通过close()关闭链接

四:内部类和外部模块等的引用

发现它的方式同内存溢出,可再加个实时观察

jstat -gcutil 7362 2500 70

重点关注:

FGC — 从应用程序启动到采样时发生 Full GC 的次数

FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)

FGC次数越多,FGCT所需时间越多-可非常有可能存在内存泄漏

3. OutOfMemoryError:unable to create new native thread

原因:线程过多

那么能创建多少线程呢?这里有一个公式:

(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads

MaxProcessMemory 指的是一个进程的最大内存

JVMMemory JVM内存

ReservedOsMemory 保留的操作系统内存

ThreadStackSize 线程栈的大小

当发起一个线程的创建时,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存:

(MaxProcessMemory - JVMMemory - ReservedOsMemory)

结论:你给JVM内存越多,那么你能用来创建的系统线程的内存就会越少,越容易发生java.lang.OutOfMemoryError: unable to create new native thread。

操作系统总内存为8G、JVM中分配内存4G/6G、保留内存345M、ThreadStackSize 为1M。

线程数=(8G-4G-345M)/1M=3751

线程数=(8G-6G-345M)/1M=1703

cat /var/log/dmesg |grep reserved #可见保留内存

java -XX:+PrintFlagsInitial >>1.txt #打印出所有JVM默认参数和值

cat 1.txt | grep ThreadStackSize #可见线程栈的大小

java oom分析_作为测试你应该知道的JAVA OOM及定位分析相关推荐

  1. mongodb java 日志分析_记一次log4j与mongodb集成引发的问题分析

    问题背景 对项目中的关键应用调用链日志需要结构化得统一吐出到mongodb中,同时项目中日志输出使用log4j,故准备使用log4j的Appender直接集成mongodb的输出,同时mongodb采 ...

  2. java bdd 框架_开发者测试: 实现BDD测试框架(JSpec)

    There are two ways of constructing a software design. One way is to make it so simple that there are ...

  3. java 清空控制台_利用原生库和JNI(Java原生接口)实现H2数据库漏洞利用

    在H2数据库引擎中获取代码执行权限的技术早已是众所周知,但有个要求就是H2能够动态编译Java代码.而本文将向大家展示以前没有公开过的利用H2的方法,并且无需使用Java编译器,即通过原生库和JNI( ...

  4. java框架核心技术_你必须掌握的 21 个 Java 核心技术!(干货)

    点击上方"java进阶架构师",选择右上角"置顶公众号" 20大进阶架构专题每日送达 51闲来无事,师长一向不(没)喜(有)欢(钱)凑热闹,倒不如趁着这时候复盘 ...

  5. java转换为c#_将25k行C#转换为Java的经验教训

    java转换为c# 由于各种原因,我最近完成了一个将复杂的财务应用程序从C#转换为Java的项目. 港口的原因大部分是非技术性的,而是对相关企业的一项战略举措. 这是一次有趣的经历,我在此过程中吸取了 ...

  6. jmeter性能分析_使用JMeter和Yourkit进行REST / HTTP服务的性能分析

    jmeter性能分析 我的上一篇文章描述了如何使用JMeter完成异步REST / HTTP服务的压力测试或负载测试. 但是,运行这样的测试通常表明被测系统不能很好地应对增加的负载. 现在的问题是如何 ...

  7. java对象模型 指令_深入理解多线程(二)—— Java的对象模型

    上一篇文章中简单介绍过synchronized关键字的方式,其中,同步代码块使用monitorenter和monitorexit两个指令实现,同步方法使用ACC_SYNCHRONIZED标记符实现.后 ...

  8. java future用法_你必须掌握的 21 个 Java 核心技术

    作者:工程师-搁浅来源:https://www.jb51.net/article/122070.htm 写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,主要是和一些java基础知 ...

  9. java 核型技术_你必须掌握的 21 个 Java 核心技术!(转自Java技术栈)

    写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,希望可以给大家一些经验,能让大家更好学习和使用Java. 这次介绍的主要内容是和J2SE相关的部分,另外,会在以后再介绍些J2EE ...

最新文章

  1. iOS SwiftUI篇-5 专题NavigationView、NavigationLink
  2. effective c++
  3. 第四届国际软件自由日在西安邮电学院的发言
  4. python安装虚拟环境没有activate_Python venv虚拟环境:Activate命令的作用
  5. HttpURLConnection 发送http请求帮助类
  6. dhcp 续约review报文_Linux的私房菜 DHCP
  7. camel mq_Camel:构建基于消息的应用程序
  8. ajax方式表单拦截
  9. mongodb mysql数据类型_mongodb中数据类型的坑
  10. 1023. 组个最小数 (20)-PAT乙级真题
  11. java 父类_java 调用父类的父类
  12. Sql中的union和union all的讲解
  13. 保护隐私型浏览器Tor发布安卓试用版
  14. 游戏本天梯_天下3:夫妻采访——吃饭睡觉打天梯
  15. 惯量比多少合适_惯量比计算公式
  16. 【Android驱动】高通msm8953背光流程
  17. Android之Surface 与 SurfaceFlinger关系
  18. Link-添加网页图标
  19. ZOJ3380 Patchouli's Spell Cards C++版(概率DP+大数)
  20. android studio自定义app图标

热门文章

  1. BERT源码分析(PART I)
  2. 顶会快讯|5篇AAAI2020相关论文抢先看(附GitHub代码地址)
  3. 这个3月我有3场见面会,不知道你来不来?
  4. TensorFlow 1.9开始支持树莓派
  5. 0 有符号和无符号整型数字
  6. 小酌重构系列[19]——分解大括号
  7. Ubuntu中如何使用root用户
  8. RHEL5.4安装Oracle-10g
  9. Microsoft Forefront EndPoint Protection 2010 Client 静默安装
  10. horizon client长时间不操作不断开_动挡操作禁忌,伤车只在一瞬间!否则变速箱会提前...