【Java虚拟机】内存溢出

Java堆溢出

Java堆用于存储对象实例,在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

  • -Xms 堆最小值

  • -Xmx 堆最大值

  • 可以通过配置参数-XX:HeapDumpOnOutOfMemoryError,在虚拟机内存溢出时Dump出当前的内存堆转储快照以便事后进行分析,Java堆内存OOM是实际应用中常见的内存溢出异常情况。可以通过内存映像分析工具(such as Eclipse Memory Analyzer),重点分析排查是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

  • 如果是内存泄漏,可以通过工具查看泄漏的对象到GC Roots的引用链,确定对象为何无法被垃圾收集器自动回收。

  • 若果不存在内存泄漏,就需要通过参数调优,对比机器物理内存,确定分配的堆内存是否可以调大,同时要从代码层间检查是否有某些对象的生命周期过长,保持的状态时间过长等情况,尝试减少程序运行期间的内存消耗。

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

Hotspot虚拟机不区分虚拟机栈和本本地方法栈,所以虽然存在-Xoss(设置本地方法栈大小),但实际不起作用。

  • -Xss 设置栈容量大小。
  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常;
  • 如果虚拟机在扩展栈的时候无法申请到足够的内存空间,将抛出OOME异常。
  • 两者存在重叠的地方,当栈空间无法继续分配时,内存太小 or used栈空间太大,is the same thing.
  • MaxPermSize 最大方法区容量
  • 程序计数器内存消耗很小,可以忽略不计
  • 栈深度在大多数情况下,达到1000-2000 完全没问题。
  • !!!在多线程并发处理的情况下,每个线程分配到的栈容量越大,可以建立的线程数就越少,建立线程时就越容易将剩余内存耗尽。在这种情况下,在不能减少线程数或者更换成64位虚拟机的情况下,能够通过减少最大堆和减少栈容量的情况下换取更多的线程。
  • 在Window平台虚拟机上,Java的线程是映射到操作系统的内核线程上的,有些线程死循环的话可能造成操作系统假死。

方法区和运行时常量池溢出

JDK1.7开始逐步"去永久代"
在JDK1.6及之前,可以通过限制方法区大小,从而间接限制常量池的容量。
String.intern(),一个Native方法,不断执行此方法往常量池中添加字符串,可以导致PermGen Space OOM,即运行时常量池属于方法区(Hotspot JVM 永久代)的一部分。
当前很多的主流框架如Spring、Hibernate,在对类进行增强的时候,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区类保证动态生成的Class可以载入的内存中。

本机直接内存溢出

DirectMemo如容量可以通过-XX:MaxDirectMemorySize 指定,默认为Java堆最大内存(-Xmx)。
由于DirectMemory导致的内存溢出,一个明显的特征就是Heap Dump文件中不会看到明显的异常,如果发现OOM之后Dump很小,而程序中又直接或者间接使用了NIO,那么可以考虑是这方面的原因。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值