当前位置: 首页 > news >正文

重温Java - Java基础二

工作中常见的6中OOM 问题

堆内存OOM

堆内存OOM 是最常见的OOM了。出现堆内存OOM 问题的异常信息如下

java.lang.OutOfMemoryError: Java heap space

此OOM是由于Java中的heap的最大值,已经不能满足需求了。

举个例子

@Test
public void test01(){
    List<OOMTest> list = Lists.newArrayList();
    while(true){
        list.add(new OOMTests());
    }
}

这里创建了一个List 集合,在一个死循环中不停的往里添加对象。

执行结果:

在这里插入图片描述

出现了java.lang.OutOfMemoryError:Java heap space 的堆内存溢出。

很多时候,execl一次性到处大量的数据,获取在程序中一次性查询的数据太多,都可能出现这种OOM的问题。

栈内存OOM

有时候,我们的业务系统创建了太多的线程,可能会导致栈内存OOM。

出现栈内存OOM 问题的异常信息如下:

java.lang.OutOfMemory:unable to create new native thread	

给举个例子:

public class StartOOMTest{
    public static void main(String[] args){
        while(true){
            new Thread().start();
        }
    }
}

使用一个死循环不停的创建线程,导致系统产生了大量的线程。

如果实际工作中出现了这个问题,一般是由于创建的线程太多了,或者设置的单个线程占用的内存空间太大导致的。

建议在日常工作中,多用线程池,少自己创建线程,防止这种OOM

栈内存溢出

我们在业务代码中可能会经常写一些递归 调用,如果递归深度超过了JVM 允许的对打深度,可能会出现占内存溢出的问题。

出现占内存溢出的异常信息如下:

java.lang.StackOverflowError

举个示例:

@Test
public void test03(){
    recursiveMethod();
}
public static void recursiveMethod(){
        recursiveMethod();
}

执行结果如下:

在这里插入图片描述

出现了java.lang.StackOverflowError栈溢出的错误

我们在写递归代码时,一定要考虑递归深度。即使是使用parentId 一层层网上找的逻辑,也最好加一个参数控制递归的深度。防止因为数据问题导致无限递归的情况,比如:id和ParentId 的值像等。

接内存OOM

直接内存 不是虚拟机运行时数据分区的一部分,也不是《Java虚拟机规范》中定义的内存区域。

它源于NIO ,通过存在堆中的DirectByteBuffer操作Native内存,是属于堆外内存 ,也可以直接想系统申请的内存空间

直接出现内存OOM 问题的异常信息如下:

java.lang.OutOfMemoryError:Direct buffer memory

例如下面这样的:

private static final int BUFFER = 1024*1024*20;
@Test
public void test04(){
    ArrayList<ByteBuffer> list = new ArrayList();
    int count = 0;
    try{
        while(true){
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
            list.add(byteBuffer);
            count++;
            try{
                Thread.sleep(300);
               
            }catch(InterruptException e){
                e.printStackTrace();
            }
        }
    }final{
        System.out.println(count);
    }
}

会看到报出来java.lang.OutOfMemoryError:Direct buffer memory 直接内存空间不足。

GC OOM

GC OOM 是由于JVM 在GC 时,对象过多,导致内存溢出,建议直接调整GC 的策略。

出现了GO OOM 问题时异常信息如下:

java.lang.OutOfMemoryError:GC overhead limit exceeded

为了方便测试,我们先将Idea中的最大和最小堆内存都设置成10M

例如下面的例子:

public class GCOverheadOOM{
    public static void main(){
        ExecutorService executor = Executors.newFixedThreadPool(5);
        for(int i = 0;i<Integer.MAX_VALUE;i++){
            executor.execute(()->{
                try{
                    Thread.sleep(10000);
                }catch(InterruptedException e){
                    
                }
            });
        }
    }
}

出现这个问题是由于JVM 在GC 的时候 ,对象太多,就会报这个错误。

我们需要改变GC 的策略。

在老代80%时就开始GC,并且将-XX:SurvivorRatio (-XX:SurvivoRatio=8)和-XX:NewRatio (-XX:NewRatio=4)设置的更合理。

元空间 OOM

JDK8 之后使用MateSpace来替代永久代,Matespace是方法区HotSpot中的实现。

Metaspace不在虚拟机内存中,而是使用本地内存也就是在JDK8的ClassMetadata ,也被存储在叫做Metaspace的Native memory。

出现元空间OOM 问题时异常信息如下:

java.lang.OutOfMemoryError:Metaspace

为了方便测试,我们修改一下idea中的JVM 参数,增加下面的配置:

-XX;MetasoaceSize=10M -XX:MaxMetaspaceSize=41m

这里指定了元空间和最大元空间都是10M。

接下来,看看下面这行例子

public class MetaspaceOOMTest{
    static class OOM{
        
    }
    public static void main(String[] args){
        int i = 0;
        try{
            while(true){
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperClass(OOM.class);
                enhancer.setUserCache(false);
                enhancer.setCallback(new MethodInterceptor(){
                    public Object interceptor(Object o,Method method,Object[] objects,MethodProxy methodProxy) throws Throwable{
                        return methodProxy.invokeSuper(o,args);
                    }
                });
                enhandcer.create();
            }
        }catch(Throwable e){
            e.printStackTrace();
        }
    }
}

程序最后汇报java.lang.OutOfMemoryError:Metaspace的元空间OOM。

这一类问题一般是由于加载到内存中的类太多,或者类的体积太大导致。

Java中的异常处理机制是怎样的

异常是在程序执行的过程中可能出现的错误或意外情况。他们通常表示了程序无法正常处理的情况,如除零错误,空指针引用、文件不存在等。

Java中异常的处理机制通过使用try-catch-finally语句块来捕获和处理异常。具体的流程如下:

  1. 使用try 块包裹可能会出现抛出异常的代码块。一旦try块中发生了异常,程序的控制流会立即跳转到与之对应的catch块
  2. 在catch块中,可以指定捕获特定类型的异常,并提供相应的处理逻辑。如果发生了指定类型的异常,程序会跳转到相应的catch块中进行处理。一个try块可以有多个catch块,分别处理不同类型的异常。
  3. 如果某个catch块成功处理了异常,程序将继续执行catch块之后的代码。
  4. 在catc块中,可以通过throw 语句重新抛出异常,将异常交给上一级的调用者处理。
  5. 可以使用finally 块来定义无论是否发生异常都需要执行的代码。finally块中的代码使用 无论异常是否被捕获。

通过合理使用异常处理机制,可以是程序更具健壮性和容错性。在处理异常时,应根据具体情况选择是否恢复正常运行,报告错误给用户,还是中止程序运行。同时应便面过度捕获异常和不处理异常导致的问题,以及使用异常代理正常的流程控制的做法。

相关文章:

  • 无人设备遥控器之通信链路管理篇
  • C++ 创建静态数组出现栈满程序崩溃的问题
  • 【虚拟机栈中的栈帧是什么?有什么作用?局部变量表、操作数栈、动态链接和方法返回地址是什么?有什么作用?为什么要放在栈帧里?】
  • Ubuntu24.04 编译 Qt 源码
  • 一个可以在Android手机上运行的Linux高仿window10的应用
  • Python中的AdaBoost分类器:集成方法与模型构建
  • VT01N/VT02N进行交货的时候,对装运点加权限控制的增强
  • 原生SSE实现AI智能问答+Vue3前端打字机流效果
  • 【语法】C++的list
  • 模糊测试究竟在干什么
  • 41、web前端开发之Vue3保姆教程(五 实战案例)
  • 结合大语言模型整理叙述并生成思维导图的思路
  • C语言--常用的链表操作
  • 分布式存储怎样提高服务器数据的安全性?
  • Vue3+Vite+TypeScript+Element Plus开发-09.登录成功跳转主页
  • CentOS8.5 LLaMA-Factory训练模型
  • ChatDBA:一个基于AI的智能数据库助手
  • 基于C8051F340单片机的精确定时1S的C程序
  • 代码随想录算法训练营--打卡day8
  • 状态同步梳理
  • 佛山做外贸网站的公司吗/漳州seo网站快速排名
  • 微信网站建设热线/互联网销售平台有哪些
  • 上海建设工程咨询协会/广东seo推广
  • 网站建设seo优化/企业网站多少钱一年
  • 咸阳网站网站建设/免费seo快速排名工具
  • 滨州网站seo服务/佛山今日头条