Java虚拟机--分析Java堆(十一)

来源:互联网 发布:最具潜力的淘宝商品 编辑:程序博客网 时间:2024/06/07 20:43
  • 找到内存溢出的原因
    • 堆溢出
      • 异常说明:因为大量对象都直接分配在堆上,绝大部分的内存溢出都属于这种情况;
      • 原因分析:因为大量对象占据了堆空间,而这些对象都持有强引用,导致无法回收,当大于Xmx参数指定的堆空间大小时,就会抛出溢出错误;
      • 示例1:

public class SimpleHeapOOM {

public static void main(String[] args) {

ArrayList<byte[]> list = new ArrayList<byte[]>();

for (int i = 0; i < 10240; i++) {

list.add(new byte[1024*1024]);

}

}

}

错误提示: Java heap space表示堆空间溢出
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

解决方案:
可以使用
-Xmx参数指定一个更大的堆空间;由于堆空间不能无限量增长,通过内存分析工具,找到大量占用堆空间的对象,进行优化才是正路!
 

  • 直接内存溢出
    • 关于直接内存看这里:直接内存
    • 原因分析:直接内存没有被Java虚拟机完全托管,若使用不当,也容易触发直接内存溢出,导致宕机;
    • 异常说明:直接内存溢出,一般抛出OutOfMemoryError错误。直接内存不一定能够触发GC(触发直接内存使用量达到了-XX:MaxDirectMemorySize的设置),所以它产生的没有被任何对象所引用的变量可能并不会被回收;
    • 解决方案:合理的使用显示GC(也就是System.gc()),或者设定一个系统实际可达的-XX:MaxDirectMemorySize值;
  • 过多线程导致OOM
    • 原因分析:每个线程的开启都要占用系统内存,线程的栈空间也是在堆外分配的,因此和直接内存非常相似;
    • 异常说明:此异常一般为"unable to create new native thread",表示系统创建线程的数量已经饱和,原因是Java进程已经达到了可使用的内存上限;
    • 解决方案:
      • 可以尝试减少堆空间,也就是减少运行参数 -Xmx的值;
      • 减少每个线程所占的内存空间,-Xss参数可以指定线程的栈空间;
        • 减少线程的栈空间大小,栈溢出的风险会响应上升;
  • 永久区溢出
    • 原因分析:永久区用来存放类元数据。如果一个系统定了太多的类型,永久区是有可能溢出的。JDK1.8中,永久区被元数据区域替代,但功能类似;
    • 异常说明:异常信息为"java.lang.OutOfMemoryError:PermGen space"
    • 解决方案:
      • 增加MaxPermSize的值;
      • 减少系统需要的类的数量;
      • 使用ClassLoader合理地装载各个类,并定期进行回收;
  • GC效率低下引起的OOM
    • 原因分析:GC是内存回收的关键,如果GC效率低下,那么系统的性能会受到严重的影响。如果系统的堆空间太小,那么GC所占的时间就会较多,并且回收所释放的内存就会较少。根据GC占用的系统时间,以及释放内存的大小,虚拟机会评估GC的效率,一旦虚拟机认为GC的效率过低,就有可能直接抛出OOM异常;
      • 一般情况下,虚拟机会根据以下几种情况来判定是否抛出此异常:
        • 花在GC上的时间是否超过了98%
        • 老年代释放的内存是否小于2%;
        • eden区释放的内存是否小于2%;
        • 最近是否连续5次GC都出现了上述几种情况(注意是同时出现,不是出现一个!);
      • 当满足以上条件,虚拟机会抛出:GC overhead limit exceeded异常
    • -XX:-UseGCOverheadLimit:来禁止这种OOM的产生;
0 0
原创粉丝点击