OOM三种类型

OOM的三种类型:

堆OOM


/**
     * -Xmx1g -XX:+PrintGCDetails -XX:MaxDirectMemorySize=100m
     *
     * @param args
     */
    public static void main(String[] args) { ArrayList<byte[]> arrayList = new ArrayList<>(); for (int i = 0; i < 1024; i++) { arrayList.add(new byte[1024 * 1024 * 2]); } } 

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.Test.main(Test.java:15)

解决方法: 增大Xmx值 使用MAT,JProfile等工具进行代码分析与优化


直接内存OOM

 /**
     * -Xmx1g -XX:+PrintGCDetails -XX:MaxDirectMemorySize=100m
     * @param args
     */
    public static void main(String[] args) { for (int i = 0; i < 2048; i++) { ByteBuffer.allocateDirect(1024 * 1024*2); System.out.println(i); //System.gc(); } } 

运行结果: 直接内存设置为2M,超过100M时,进行回收

解决方法: 增大MaxDirectMemorySize的值


过多线程导致的OOM

 /**
     * -Xmx1g -XX:+PrintGCDetails 
     -XX:MaxDirectMemorySize=100m
     -Xss:指定栈空间大小
     *
     * @param args
     */
    public static void main(String[] args) { for (int i = 0; i <1500 ; i++) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } } 

运行结果: OOM unable to create native thread

解决方法: 减少线程数、或减少堆空间与线程空间


永久(Pern)溢出

永久区是存储类元数据的区域

/**
     * -Xmx1g -XX:+PrintGCDetails 
     *
     * @param args
     */
    public static void main(String[] args) { for (int i = 0; i < 1000000000; i++) { Integer integer = new Integer("1" + new StringBuffer(1)); System.out.println(new ArrayList<>()); } } 

运行结果: OOM Permgen sace 解决方法:

  • 增大MaxPremSize的值
  • 减少系统需要的类的数量
  • 使用ClassLoader合理装载类,并进行回收

GC效率低下引起的OOM

判断GC引起OOM的条件

  1. 花在GC上的时间是否超过了98%
  2. 老年代释放的内存是否小于2%
  3. Eden区释放的内存是否小于2%
  4. 是否连续5次GC都出现了上述几种情况

关闭OOM可以通过参数:-XX:-UseGCOverheadLimit 进行设置

String常量池因其的OOM


 /**
     * -Xmx5m -XX:MaxPermSize5m【JDK<1.6】
     *
     * @param args
     */
    public static void main(String[] args) { List<String> list = new ArrayList<>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } } 

运行结果: JDK1.6 :Perm space JDK1.7 :heap space

【注】

 /**
     *String.intern()方法返回字符串常量池引用,但不一定每时每刻都返回一样,可能垃圾回收后重新放入常量池
     *
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(System.identityHashCode((args[0] + Integer.toString(0))));//字符本身hash System.out.println(System.identityHashCode((args[0] + Integer.toString(0)).intern()));//常量池引用 System.gc();//未gc前常量池引用相同 System.out.println(System.identityHashCode((args[0] + Integer.toString(0)).intern()));//常量池引用 } 

浅堆和深堆

浅堆(shallow heap):一个对象结构所占的内存大小,对象包括属性和对象头、对象引用等。

如String对象,其结构包括:
类型大小
inthash320
inthash0
refvaluec://...

其中2个int8字节 对象引用4字节 对象头8字节 按照8字节对齐,则对象浅堆共24字节

深堆(retained heap):一个对象被GC回收后,可以真实释放的内存大小。即对象所持有的对象和包括对象自身的所有的浅堆的大小之和。

从图中可以看出对象A的浅堆大小为A本身,对象A的实际大小为对象A、对象B、对象C、对象D的浅堆大小之和,对象A的深堆大小为对象A和对象C,因为对象B和对象D同时也被对象E所引用

转载于:https://www.cnblogs.com/htkj/p/10932489.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值