Java内存区域与内存溢出异常

2 篇文章 0 订阅

运行时数据区域

Java运行时数据区域主要包括虚拟机栈、本地方法栈、程序计数器、方法区、堆。其中,方法区和堆是所有线程共享的数据区,虚拟机栈、本地方法栈和程序计数器是线程隔离的。如下图:

在这里插入图片描述

程序计数器

程序计数器是一块较小的内存空间,可以看作是当前线程执行字节码的行号指示器。每条线程都需要一个独立的程序计数器。同时程序计数器是唯一一个没有规定OOM(OutOfMemoryError)情况的区域。## 虚拟机栈虚拟机栈和程序计数器都是线程私有的,生命周期与线程相同。每个方法JVM都会同步创建一个栈帧。存储局部变量表、操作数栈、动态连接和方法出口

本地方法栈

本地方法栈和虚拟机栈类似,虚拟机栈为虚拟机执行的Java方法(字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。## 堆堆是所有线程共享的一块内存区域(也可以划分TLAB给线程私有,以提高对象分配时的效率),此区域主要存放对象实例。在JDK 7中,把原本放在方法区(永久代)中的字符串常量池、静态变量移动到了堆中。

方法区

方法区也是线程共享区域,用来存储被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码缓存的数据。

实战OutOfMemoryError异常

虚拟机启动参数设置

  • -Xms20M:Java堆的最小大小为20MB
  • -Xmx20M:Java堆的最小大小为20MB
  • -Xmn10M:设置新生代的大小为10MB
  • -Xss128K:设置栈容量为128KB
  • -XX:SurvivorRatio=8:伊甸园区(Eden)和幸存者区(Survivor)的比例为8:1
  • -XX:+PrintGCDetails:打印详细的GC信息
  • -XX:+HeapDumpOnOutOfMemoryError:出现内存溢出异常时Dump出当前内存堆转储快照

Java堆溢出

Java堆用来存储对象的实例,只要不断地创建对象,并且保证GC Root到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么随着对象数量的增加,总容量触及最大堆的容量限制后就会缠身内存溢出异常。

import java.util.ArrayList;
import java.util.List;


/**
 ** -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
*/
public class HeapOOM {

    static class OOMObject {}

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

在这里插入图片描述
使用MAT进行分析可以得到如下所示的图:
在这里插入图片描述
可以看到主线程的局部变量占据了太多的内存。

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

《Java虚拟机规范》中描述了如下两种异常:

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,是将抛出StackOverflowEror异常。
  2. 如果虚拟机的栈内存允许动态扩容的话,当扩展栈容量无法申请到足够的内存时,将抛出是OutOfMemoryError异常。
    注意:由于HotSpot虚拟机选择不支持扩展,所以无法产生OOM。

1.验证StackOverflowEror异常。

/**
 * -Xss128K
 */
public class JavaVMStackSOF {
    public void stackLeak() {
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF j = new JavaVMStackSOF();
        j.stackLeak();
    }
}

在这里插入图片描述

2.验证无法产生OutOfMemoryError异常。

通过-Xss减少内存容量,之后定义大量本地变量增大局部变量表的长度。

public class JavaVMStackSOF {

    private static int stackLength = 0;

    public static void test(){
        long var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15,
                var16, var17, var18, var19, var20, var21, var22, var23, var24, var25, var26, var27, var28, var29, var30,
                var31, var32, var33, var34, var35, var36, var37, var38, var39, var40, var41, var42, var43, var44, var45,
                var46, var47, var48, var49, var50, var51, var52, var53, var54, var55, var56, var57, var58, var59, var60,
                var61, var62, var63, var64, var65, var66, var67, var68, var69, var70, var71, var72, var73, var74, var75,
                var76, var77, var78, var79, var80, var81, var82, var83, var84, var85, var86, var87, var88, var89, var90,
                var91, var92, var93, var94, var95, var96, var97, var98, var99, var100;
        test();
        var1 = var2 = var3 = var4 = var5 = var6 = var7 = var8 = var9 = var10 = var11 = var12 = var13 = var14 = var15 =
                var16 = var17 = var18 = var19 = var20 = var21 = var22 = var23 = var24 = var25 = var26 = var27 = var28 =
                        var29 = var30 = var31 = var32 = var33 = var34 = var35 = var36 = var37 = var38 = var39 = var40 =
                                var41 = var42 = var43 = var44 = var45 = var46 = var47 = var48 = var49 = var50 = var51 =
                                        var52 = var53 = var54 = var55 = var56 = var57 = var58 = var59 = var60 = var61 =
                                                var62 = var63 = var64 = var65 = var66 = var67 = var68 = var69 = var70 =
                                                        var71 = var72 = var73 = var74 = var75 = var76 = var77 = var78 =
                                                                var79 = var80 = var81 = var82 = var83 = var84 = var85 =
                                                                        var86 = var87 = var88 = var89 = var90 = var91 =
                                                                                var92 = var93 = var94 = var95 = var96 =
                                                                                        var97 = var98 = var99 = var100 = 0;
    }

    public static void main(String[] args) {
        try {
            test();
        } catch (Error e) {
            System.out.println("stack length:" + stackLength);
            throw e;
        }
    }
}

实验结果图:(可以看出依然是StackOverflow异常)
在这里插入图片描述

方法区溢出

通过动态产生类造成方法区溢出或借助于CGLib直接操作字节码运行时生成大量的动态类。

本机直接内存溢出

暂时不会。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的内存溢出是指应用程序中存在无法回收的内存或使用的内存过多,导致程序运行所需的内存超过了虚拟机能提供的最大内存限制。\[1\]在Java中,主要有两个区域内存溢出相关,即Java堆和方法区。Java堆主要用于存放对象实例和数组等,而方法区则用于保存类信息、常量、静态变量等。运行时常量池也是方法区的一部分。这两个区域是线程共享的,当它们无法分配足够的内存时,就会抛出OutOfMemoryError异常。\[2\] 要模拟Java部分接口的内存溢出,可以在程序中创建一个循环,不断地将字符串进行拼接,直到内存溢出。例如,可以使用以下代码来模拟内存溢出的逻辑: ```java @RequestMapping("/testOutOfMemory") @ResponseBody public void testOutOfMemory() throws Exception { String name = "Aikes"; for (int i = 0; i < 10000000; i++) { name += name; } System.out.println(name); } ``` 在这段代码中,我们通过循环将字符串`name`不断地与自身进行拼接,使其不断增长,直到超过虚拟机所能提供的最大内存限制,从而导致内存溢出。\[3\] #### 引用[.reference_title] - *1* *2* [java内存溢出](https://blog.csdn.net/u014401141/article/details/122825443)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Java内存溢出问题排查分析](https://blog.csdn.net/AikesLs/article/details/124290879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值