JVM 深入理解 - 内存溢出

6 篇文章 0 订阅


Java 学习目录
上一章 JVM 深入理解 - 字符串常量池

本机直接内存溢出

  • 设置方法:-XX:MaxDirectMemorySize=size
    本机直接内存可以通过上面的参数进行设置(默认与堆内存最大值一样),所以也会出现 OOM 异常。
  • 由直接内存导致的内存溢出,一个比较明显的特征是在 HeapDump 文件中不会看见有什么明显的异常情况,如果发生了 OOM,同时 Dump 文件很小,可以考虑重点排查下直接内存方面的原因。

栈溢出

  • 设置方法: -Xss1m
    注:HotSpot 版本中栈的大小是固定的,是不支持拓展的。
  • 明显异常:java.lang.StackOverflowError
  • 触发方式: 一般的方法调用是很难出现的,除非方法无限递归。
  • 解决办法:
    1. 查找有无无限递归方法,找到后处理掉。
    2. 如果是正常情况的话,那就要加大内存。
  • 题外话:递归与循环。
    由于jvm 设计规则。所以同样的功能使用循环一定比递归要快,因为要不停地打包成栈帧压入栈中。因为要不停地打包成栈帧压入栈中。
  • 同时要注意,栈区的空间 JVM 没有办法去限制的,因为 JVM 在运行过程中会有线程不断的运行,没办法限制,所以只限制单个虚拟机栈的大小。
/**
 * 栈溢出  -Xss=1m
 */
public class StackOverFlow {

    public void dance(int a){//方法不断执行-栈帧不断入栈(不出栈)
    	System.out.println(a);
        dance(++a);//
    }
    public static void main(String[] args)throws Throwable {
        StackOverFlow javaStack = new StackOverFlow();
        javaStack.dance(1);
    }
}

在这里插入图片描述
当调整栈内存大小后会有所改善,但是还是要预防无限递归。

堆溢出

  • 设置方法:-Xms;-Xmx;
  • 明显异常:java.lang.OutOfMemoryError:java heap space
  • 触发方式:
    1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
    2. 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
    3. 代码中存在死循环或循环产生过多重复的对象实体;
    4. 使用的第三方软件中的BUG;
    5. 启动参数内存值设定的过小;
  • 解决办法:
    1. 检查是否有方法异常创建对象,有引用而不使用。
    2. 增加内存。
    3. 适当增加其他引用关系。
/**
 * VM Args:-Xms30m -Xmx30m -XX:+PrintGCDetails
 * 堆内存溢出(直接溢出)
 */
public class HeapOom {
   public static void main(String[] args)
   {
       String[] strings = new String[35*1000*1000];  //35m的数组(堆)
   }
}

在这里插入图片描述

方法区溢出

  • 运行时常量池溢出
  • 方法区中保存的 Class 对象没有被及时回收掉或者 Class 信息占用的内存超过了我们配置。
  • 注意 Class 要被回收,条件比较苛刻(仅仅是可以,不代表必然,因为还有一些参数可以进行控制)
    1. 该类所有的实例都已经被回收,也就是堆中不存在该类的任何实例。
    2. 加载该类的 ClassLoader 已经被回收。
    3. 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
 * 方法区导致的内存溢出
 * VM Args: -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M
 * */
public class MethodAreaOutOfMemory {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(TestObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object arg0, Method arg1, 
                Object[] arg2, MethodProxy arg3) throws Throwable {
                    return arg3.invokeSuper(arg0, arg2);
                }
            });
            enhancer.create();
        }
    }

    public static class TestObject {
        private double a = 34.53;
        private Integer b = 9999999;
    }
}

在这里插入图片描述

  • -Xnoclassgc 禁用类的垃圾收集(GC)
    在这里插入图片描述

Java 学习目录
下一章 JVM 深入理解 - 对象 “对象”?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值