01.JVM内存区域

01.JVM内存区域

0101.运行时数据区

  • 程序计数器
    • 存储:下一段要执行的代码的地址
    • 共享:线程私有
    • 特点:占用非常小的内存空间
    • OOM:唯一不会出现OOM的区域
  • 虚拟机栈:
    • 存储:
      • 方法执行的线程内存模型,入栈和出栈,对应的是方法的调用和退出;
      • 局部变量表:存储基本类型和引用类型、返回地址。
    • 共享:线程私有
    • OOM:
      • SOF:
        • 在入栈深度超过额定值会触发
        • 线程内内存用完,没有地方放新的栈帧
      • OOM:
        • 要申请新线程会触发
        • 线程要扩内存,但是没有足够的内存会触发(HotSpot不支持线程扩内存)
  • 本地方法栈:
    • 同虚拟机栈:
    • 不同点:只存储本地方法调用的相关信息。
  • 堆:
    • 存储:
      • 几乎所有的对象实例和数组
      • 字符串常量池、类文件常量池
      • 静态变量
    • 共享:线程共享
    • OOM:堆内存用完了,并且堆内存无法扩展。
    • 特点:堆分为年轻代和老年代;年轻代分为Eden区和S0、S1区;Eden区中又包含TLAB区;TLAB区是线程私有的。
  • MetaSpace(元数据区):
    • 存储:
      • 运行时常量池(类信息)
    • 共享:线程共享
    • OOM:
      • 元数据区进行垃圾回收后,需要扩容,但是又没有足够的内存扩容时,会导致OOM
      • 动态代理无限生成代理类,会导致OOM
      • JSP文件运行时,生成大量的类文件
    • 特点:如果不设置上限,则默认剩余的机器内存有多大,我就有多大。
  • 直接内存:
    • 存储:通过NIO直接分配对外内存
    • 共享:在于对应的DirectByteBuffer的引用是否共享
    • OOM:机器内存不足时,会OOM。
    • 特点:不属于运行时数据区,并且OOM时,是因为系统判定要申请的内存不足,并不是自己去申请内存申请不到。

0102.特殊情况

010201 对象只是几乎全部在堆中,并非真的全部在堆中:
  • 原因:逃逸分析
  • 解释:
    • 逃逸分析主要是用来判定指针或者对象,被使用的方法
    • 举个例子:我们定义了一个局部对象,但是放到了全局数组里,那么就逃逸出了当前线程。
    • 如果判断对象没有逃逸出当前线程,那么就可以把对象分配到栈空间,在线程声明周期结束的时候,直接回收栈空间,就避免了GC,这个分配到栈空间的行为就叫做栈上分配。
    • 如果对象没有逃逸出当前线程,并且对象本身并没有被使用,只是对象中的部分属性被使用,则只会在栈上创建对象被使用的部分属性,而不会创建整个对象,这个现象叫做标量替换。

示例代码

public class Test {

    public static final List<User> USER_LIST = new ArrayList<User>();

    /**
     * 线程逃逸
     */
    public void show(){
        User user = new User();
        USER_LIST.add(user);
    }

    /**
     * 方法逃逸
     */
    public User show1(){
        User user = new User();
        return user;
    }

    /**
     * 栈上分配
     */
    public void see(){
        User user = new User();
        System.out.println(user.getClass().getName());
    }

    /**
     * 标量替换
     */
    public void seeId(){
        User user = new User();
        System.out.println(user.id);
    }

}

class User{
    int id;
}
010202 从G1垃圾收集器开始,分代回收思想就不再是唯一的堆内存布局

堆分为年轻代和老年代;年轻代分为Eden区和S0、S1区;Eden区中又包含TLAB区;TLAB区是线程私有的。

上边这种说法就不完全正确了。

0103.制造OOM

010301. 栈深度超出导致SOF
public class SOFFromStack {

    public static void main(String[] args) {
        show();
    }

    public static void show(){
        show();
    }
}

Exception in thread "main" java.lang.StackOverflowError
   at com.memorys.mybook.coding.jvm.oom.SOFFromStack.show(SOFFromStack.java:15)
   at com.memorys.mybook.coding.jvm.oom.SOFFromStack.show(SOFFromStack.java:15)
   at com.memorys.mybook.coding.jvm.oom.SOFFromStack.show(SOFFromStack.java:15)
010302. 没有足够的内存来创建新线程
public class OOMFromStack {

    public static void main(String[] args) {
        System.out.println("---start--");
        show();
        System.out.println("---end--");
    }

    /**
     *
     * 没有足够的内存来申请新线程
     */
    public static void show(){
        while (true){
            final Thread thread = new Thread(new Runnable() {
                public void run() {
                    System.out.println("new Thread " + Thread.currentThread().getName());
                    while (true){

                    }
                }
            });

            thread.start();
        }
    }
}

经常会导致机器卡死
Exception in thread "main" java.lang.OutOfMemoryError: unable to create native thread
010303. 堆内存不足溢出
public class HeapOOM {

    /**
     * @param args -Xms20M -Xmx20M
     */
    public static void main(String[] args) {
        List<Object> list = new ArrayList<Object>();

        while (true){
            list.add(new Object());
        }
    }
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
   at java.util.Arrays.copyOf(Arrays.java:3210)
   at java.util.Arrays.copyOf(Arrays.java:3181)
010304. 元空间溢出
public class MetaspaceOOM {

    /**
     * @param args -XX:MaxMetaspaceSize=10M
     * 利用Cglib不断生成代理类来增大元空间占用的内存
     */
    public static void main(String[] args) {

        while (true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMClass.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invoke(0,objects);
                }
            });
            enhancer.create();

        }
    }
}

class OOMClass{

}


Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
   at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:348)
   at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
   at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:117)
   at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
   at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
   at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
   at com.memorys.mybook.coding.jvm.oom.MetaspaceOOM.main(MetaspaceOOM.java:27)
Caused by: java.lang.reflect.InvocationTargetException
   at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   at java.lang.reflect.Method.invoke(Method.java:498)
   at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:459)
   at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:339)
   ... 6 more
Caused by: java.lang.OutOfMemoryError: Metaspace
   at java.lang.ClassLoader.defineClass1(Native Method)
   at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
   ... 11 more
010305. 直接内存溢出
public class DiretMemoryOOM {

    public static void main(String[] args) throws IllegalAccessException {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true){
            unsafe.allocateMemory(1024 * 1024 * 1024);
        }
    }
}

特点:没有明显的OOM错误信息,堆内存Dump文件无异常,
Exception in thread "main" java.lang.OutOfMemoryError
   at sun.misc.Unsafe.allocateMemory(Native Method)
   at com.memorys.mybook.coding.jvm.oom.DiretMemoryOOM.main(DiretMemoryOOM.java:19)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值