JVM OOM


JVM内存溢出分为两种情况: OutOfMemoryErrorStackOverflowError

  • OutOfMemoryError是在程序无法申请到足够的内存的时候抛出的异常
  • StackOverflowError是线程申请的栈深度大于虚拟机所允许的深度所抛出的异常

java.lang.OutOfMemoryError:Java heap space 堆内存溢出
解决办法:设置堆内存大小,设置jvm值的方法是调大-Xms(堆的最小值),-Xmx(堆的最大值)

java.lang.StackOverflowError 栈内存溢出
栈溢出产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。解决办法:
设置线程最大调用深度:-Xss5m

栈溢出几种情况及解决方案:
一、局部数组过大。当函数内部的数组过大时,有可能导致堆栈溢出。
二、递归调用层次太多。递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致堆栈溢出。
三、指针或数组越界。例如进行字符串拷贝或处理用户输入等等。

解决这类问题的办法有两个,一是增大栈空间,二是改用动态分配,使用堆(heap)而不是栈(stack)。

内存溢出发生的区域

  • Program Counter Regster(程序计数器):每一个用户线程对应一个程序计数器,用来指示当前线程所执行字节码的行号。由程序计数器给文字码解释器提供下一条要执行的字节码的的位置。根据jvm规范,这个区域不会发生内存溢出
  • Java stack(java 虚拟机栈):这个区域是最容易出现内存异常的区域,每一个线程对应生成一个线程栈,线程每执行一个方法的时候,都会创建一个栈帧,用来存放方法的局部变量表,操作树栈,动态连接,方法入口。jvm规范对这个区域定义了两种内存异常。如果虚拟机在扩展栈时无法申请到足够的内存空间则抛出OutOfMemoryError如果线程请求的栈深度大于虚拟机所允许的最大深度,将会抛出StackOverflowError
  • Native MethodStack(本地方法栈):和虚拟机栈一样,不同的是处理的对象不一样,虚拟机栈处理java的字节码,而本地栈则是处理的Native方法。其他方面一致
  • Heap(堆):前面说了堆是所有线程都能访问的,随着虚拟机的启动而存在,这块区域很大,因为所有的线程都在这个区域保存实例化的对象,因为每一个类型中,每个接口实现类需要的内存不一样,一个方法内的多个分支需要的内存也不尽相同,我们只有在运行的时候才能知道要创建多少对象,需要分配多大的地址空间。GC关注的正是这样的部分内容,所以很多时候也将堆称为GC堆。堆中肯定不会抛出StackOverflowError类型的异常,所以只有OutOfMemoryError相关类型的异常
  • Method Area(方法区):用于存放已被虚拟机加载的类信息,常量,静态方法,即使编译后的代码。由于早期的 Hotspot JVM 实现,很多人习惯于将方法区称为永久代(Permanent Generation)。这个区域只能抛出OutOfMemoryError类型的错误,OutOfMemoryError: PermGen space。
解决方法: 手动设置MaxPermSize大小修改TOMCAT_HOME/bin/catalina.sh
JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m"

元空间发生OOM
Metaspace 是存类/方法的加载信息的,发生OOM的可能原因:
1.Metaspace 设置小了
2.持续创建类 导致Metaspace 元空间不够用

Metaspace 元空间是什么参数决定的?

-XX:MaxMetaspaceSize=100m

内存泄漏

内存泄漏和内存溢出的区别和联系

1、内存泄漏指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出
2、内存溢出指程序申请内存时,没有足够的内存供申请者使用,此时就会报错OOM
3、内存泄漏的堆积最终会导致内存溢出

Java发生内存泄漏的情况

1、静态集合类引起内存泄漏
  像HashMap等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,引用的所有对象也不会被释放
2、监听器
  一个应用当中会用到很多监听器,我们会调用一个控件的监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会
3、单例模式
  单例对象在初始化后将在JVM的整个生命周期中存在,如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收,导致内存泄漏
4、各种连接
  比如数据库连接、网络连接(socket)和io连接,除非显式调用了close()方法将其连接关闭,否则是不会自动被GC回收的

内存泄漏排查

1.首先用top,TOP命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况。top命令提供了实时的对系统处理器的状态监视.它将显示系统中CPU最“敏感”的任务列表.该命令可以按CPU使用.内存使用和执行时间对任务进行排序
2. 利用jstack -l < pid> 查看那些cpu使用率过高的线程,看是否大多数是gc线程,如果是说明gc过于频繁,而且耗时过长,导致应用线程被挂起,无法响应客户端发来的请求,这种情况就应该是内存泄露的问题了。
3. 用jmap讲进程的堆转储文件dump出来到heap.bin文件中,然后用Eclipse Memory Analyzer (MAT)打开堆转储文件进行分析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值