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

本文介绍了JAVA OOM的三种类型: PermGen space、Java heap space、unable to create new native thread,以及对应的处理方法。例如, PermGen space 问题可通过增加XX:PermSize和XX:MaxPermSize参数解决,Java heap space 问题可能由于对象过多导致,需要检查程序或增加Xms和Xmx参数。此外,还提到了线程过多引发的OutOfMemoryError:unable to create new native thread,并给出了计算线程数的公式。
摘要由CSDN通过智能技术生成

上周现网一个内存溢出问题导致应用服务器每隔一小时死一次,遂整理下常见的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)。

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

28935cbfbae0

内存溢出.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 #可见线程栈的大小

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值