「javaoom排查」java oom排查思路

博主:adminadmin 2023-01-20 13:15:12 459

本篇文章给大家谈谈javaoom排查,以及java oom排查思路对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

如何定位OutOfMemory的根本原因

分析工具

1) 动态分析工具

jprofile

2) 静态分析工具

a: 在启动java的时候加上参数-xx:+heapdumponoutofmemoryerror,这样如果由于oom导致jvm crash的时候可以便于我们分析,生成的heap dump文件名字的命名规范如下, java_pidxxxx.hprof

b: 工具1 elcipsemat

2 ibm heap ana java -xmx1600 -jar ha396.jar

2 java 内存机制和exception实例

1对于从事c、c++程序开发的开发人员来说,担负着每一个对象生命开始到终结的维护责任。

对于java程序员来说,不需要在为每一个new操作去写配对的delete/free,不容易出现内容泄漏和内存溢出错误。不过,也正是因为java程序员把内存控制的权力交给了jvm,一旦出现泄漏和溢出,如果不了解jvm是怎样使用内存的,那排查错误将会是一件非常困难的事情。下面介绍一下java出现的oom有关的 exception和可能出现的方式

a exception in thread "main" java.lang.outofmemoryerror: permgen space

public static void main(string[] args) {

//使用list保持着常量池引用,压制full gc回收常量池行为

liststring list = new arrayliststring();

// 10m的permsize在integer范围内足够产生oom了

int i = 0;

while (true) {

list.add(string.valueof(i++).intern());

}

}

这一部分用于存放class和meta的信息,class在被 load的时候被放入permgen space区域(包括常量池:静态变量),它和和存放instance的heap区域不同,gc(garbage collection)不会在主程序运行期对permgen space进行清理,所以如果你的app会load很多class的话,就很可能出现permgen space错误动态生成的类,加载如spring、hibernate对类进行增强时,都会使用到cglib这类字节码技术,

此文来自: 马开东博客 转载请注明出处 网址:

当增强的类越多,就需要越大的方法区用于保证动态生成的class可以加载入内存。

b java.lang.outofmemoryerror: java heap space,被缓存的实例(cache)对象,大的map,list引用大的对象等等,都会保存于此

public static void main(string[] args) {

liststring list = new arrayliststring();

int i = 0;

while (true) {

list.add(new string(“test”));

}

}

c exception in thread "main" java.lang.stackoverflowerror

栈帧太多,也就是函数调用层级过多)导致。检查是否有死递归的情况~

/**

* vm args:-xss128k

*/

public class javavmstacksof {

private int stacklength = 1;

public void stackleak() {

stacklength++;

stackleak();

}

public static void main(string[] args) throws throwable {

javavmstacksof oom = new javavmstacksof();

try {

oom.stackleak();

} catch (throwable e) {

system.out.println("stack length:" + oom.stacklength);

throw e;

}

}

}

记一次jvm堆外内存OOM的解决过程

本文记录一次堆外内存OOM的排查过程。

周末的时候同事对线上服务进行了一次扩容,本以为只是简单增加几个实例而已,结果新实例接入流量后疯狂报警,只能马上切换下线,查看日志后发现如下错误:

至此堆外内存使用量过高的问题解决了,那么fullgc过多的问题是怎么回事呢,线上的gc日志是打开的,拉下来一份看了下,如下图所示:

查看了jdk的源码发现 ByteBuffer#allocateDirect 的过程中确实有一个 System.gc() 的调用,对比上边图1的调用栈可以确定是这里触发的fgc,也就是说fgc的问题其实是堆外内存OOM的副产品,堆外内存OOM的问题解决这个问题也会迎刃而解,至此问题原因排查清楚了。

那么为什么老实例和新实例会表现不一样呢,线上的实例并没有出现OOM的错误日志呢,问题的关键在于存储服务的client初始化后便不再变动,新实例初始化时比旧实例的连接数多,恰好到达了6G堆外内存上限附近,而netty的堆外内存是动态申请的,初始化时机比前者晚,请求进来时再申请堆外内存时没有可用的堆外内存了,触发了fgc,最终抛出了OOM。

如何检查和解决java虚拟机内存溢出的问题

一,jvm内存区域

1, 程序计数器

一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器。

2, java栈

与程序计数器一样,java栈(虚拟机栈)也是线程私有的,其生命周期与线程相同。通常存放基本数据类型,对象引用(一个指向对象起始地址的引用指针或一个代表对象的句柄),reeturnAddress类型(指向一条字节码指令的地址)

栈区域有两种异常类型:如果线程请求的栈深度大于虚拟机所允许的深度,将抛StrackOverflowError异常;如果虚拟机栈可以动态扩展(大部分虚拟机都可动态扩展),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError异常。

3, 本地方法栈

与虚拟机栈作用很相似,区别是虚拟机栈为虚拟机执行java方法服务,而本地方法栈则是为虚拟机用到的Native方法服务。和虚拟机栈一样可能抛出StackOverflowError和OutOfMemoryError异常。

4, java堆

java

Heap是jvm所管理的内存中最大的区域。JavaHeap是被所有线程共享的一块内存区域,在虚拟机启动时创建。主要存放对象实例。JavaHeap

是垃圾收集器管理的主要区域,其可细分为新生代和老年代。如果在堆中没有内存完成实例分配,并且也无法再扩展时,会抛出OutOfMemoryError

异常。

5, 方法区

与javaHeap一样是各个线程共享的内存区域,用于存放已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。当方法区无法满足内

存分配的需求时,将抛出OutOfMemoryError异常。方法同时包含常听说的运行时常量池,用于存放编译期生成的各种字面量和符号引用。

6, 直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是java虚拟机规范中定义的内存区域,是jvm外部的内存区域,这部分区域也可能导致OutOfMemoryError异常。

二,jvm参数

-Xss(StackSpace)栈空间

-Xms ,-Xmx(heap memory

space)堆空间:Heap是大家最为熟悉的区域,他是jvm用来存储对象实例的区域,Heap在32位的系统中最大为2G,其大小通过-Xms和

-Xmx来控制,-Xms为jvm启动时申请的最小Heap内存,默认为物理内存的1/64,但小于1G,-Xmx为jvm可申请的最大的Heap内存,

默认为物理内存的1/4,一般也小于1G,默认当空余堆内存小于40%时,jvm会最大Heap的大小到-Xmx指定大小,可通过

-XX:MinHeapFreeRatio来指定这个比例,当空余堆内存大于70%时,JVM会将Heap的大小往-Xms指定的大小调整,可通过

-XX:MaxHeapFreeRatio来指定这个比例,但通常为了避免频繁调整HeapSize的大小,将-Xms和-Xmx的值设为相同。

-XX:PermSize -XX:MaxPermSize :方法区持久代大小: 方法区域也是全局共享的,在一定的条件下它也会被 GC ,当方法区域需要使用的内存超过其允许的大小时,会抛出 OutOfMemory 的错误信息。

三,常见内存溢出错误解决办法

1, OutOfMemoryError异常

除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能,

Java Heap 溢出

一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess

java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。

出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory

Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory

Leak)还是内存溢出(Memory Overflow)。

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。于是就能找到泄漏对象时通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。

如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。

2, 虚拟机栈和本地方法栈溢出

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

这里需要注意当栈的大小越大可分配的线程数就越少。

3, 运行时常量池溢出

异常信息:java.lang.OutOfMemoryError:PermGen space

如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于

此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String

对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量

池的容量。

4, 方法区溢出

方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。

异常信息:java.lang.OutOfMemoryError:PermGen space

方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。

jvm故障排查

背景:

   服务在正常运营中,偶尔出现进程被杀死的情况,所以总结一下排查问题的方法

1.应用日志

   如:根据配置的logback-spring,logback配置的日志路径下去寻找

2.容器日志

  如:tomcat崩溃,去catalina.201X-XX-XX.log,localhost.201X-XX-XX.log等容器配置的日志文件中寻找

3.JVM奔溃日志

  当JVM发生致命错误导致崩溃时,会生成一个hs_err_pid_xxx.log这样的文件,该文件包含了导致 JVM crash 的重要信息,我们可以通过分析该文件定位到导致 JVM Crash 的原因,修复

  默认情况下,该文件是生成在工作目录下的,当然也可以通过 JVM 参数指定生成路径:

 -XX:ErrorFile=/var/log/hs_err_pid.log

4.系统日志

  (1)系统报错日志:/var/log/messages

     top查看资源占用情况(M排序由高到低)这是实时的参考率不大

     OOM killer(Out Of Memory killer),这个东西会在系统内存耗尽的情况下跳出来,选择性的干掉一些进程以求释放一些内存

     OOM killer是通过/proc/pid/oom_score这个值来决定哪个进程被干掉的。这个值是系统综合进程的内存消耗量、CPU时间(utime + stime)、存活时间(uptime - start time)         和oom_adj计算出的,消耗内存越多分越高,存活时间越长分越低。总之,总的策略是:损失最少的工作,释放最大的内存同时不伤及无辜的用了很大内存的进程,并且杀掉的进         程数尽量少。

   我们可以开启dump core 和 启动配置内存泄露的jvm参数获取dump文件的方式获取错误资料,core和dump是可以互转的

  1)dumo core

    ulimit -c unlimited(开启)

     在/usr/local/apps/获取core文件

    gdb java core分析

  2)dump

    内存泄漏是指本应该被GC回收的无用对象没有被回收,导致的内存空间的浪费,当内存泄露严重时会导致OOM

    启动时配置jvm参数

   -XX:+HeapDumpOnOutOfMemoryError

   -XX:HeapDumpPath=/xx/java.hprof;

     注:+HeapDumpOnOutOfMemoryError  需要放在-jar前面

     如java  -XX:+PrintGCDetails  -XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/xx/java.hprof  -jarxx-1.0-SNAPSHOT.jar

     出现异常,可以去找配置路径的dump快照文件,接下来借助VisualVM这种可视化工具分析就行,定位问题。

(2)内核日志:dmesg

        去内核日志里头查询。有时Linux系统或者系统上运行的java或者其它进程,会发生一些莫名其妙的问题,比如突然挂掉了,比如突然重启等等。在软件上找不到问题所在,此时     我们应该怀疑硬件或者内核的问题,此时我们就可以使用 dmesg来查看:

  dmesg | grep java

   输出如下

记录一次MetaSpace OOM问题排查历程

首先是监控告警。随后查看监控发现 cpu飙升

然后此台应用挂掉

1、日志提醒 metaspace oom,并且频繁出现

1、使用jdk命令:jmap -clstats pid 打印类加载信息,显示有较多:com.alibaba.fastjson.util.ASMClassLoader

其实easyopen框架在@Api注解上已经提供了wrapResult = true/false的能力。

java oom异常怎么解决方案

在 Java中,JavaVM拥有自动管理内存的功能,Java的GC能够进行垃圾回收,但是Android中如果ImageView使用过多的Bitmap的话,经常会报OOM(内存溢出)。

造成内存溢出及解决方案:

1.使用BitmapFactory.decodeStream替代createBitmap方法

原因是该方法直读取图片字节,调用JNInativeDecodeAsset()来完成decode,无需再使用java层的createBitmap。

2.使用压缩读取技术

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeFile(imageSdUri, options);

final int height = options.outHeight;

final int width = options.outWidth;

options.inSampleSize = 1;

int w = 320;

int h = 480;

h = w*height/width;//计算出宽高等比率

int a = options.outWidth/ w;

int b = options.outHeight / h;

options.inSampleSize = Math.max(a, b);

options.inJustDecodeBounds = false;

Bitmap bitmap = BitmapFactory.decodeFile(imageSdUri, options);

3.及时释放Bitamp

Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null.虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。但是我它应该还是能大大的加速Bitmap的主要内存的释放。

javaoom排查的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java oom排查思路、javaoom排查的信息别忘了在本站进行查找喔。