字符常量过多怎么解决,常见的字符常量怎么判断

首页 > 数码 > 作者:YD1662024-04-26 12:49:02

字符常量过多怎么解决,常见的字符常量怎么判断(1)

作为一个面向对象的编程语言,Java提供了自动的内存管理机制,这也成为了很多面试官最喜欢问的问题。从内存管理的角度来谈谈Java语言的优势?

相比较于C语言通过手动去申请、使用、释放内存来讲,Java最大的优势就在于其对于内存的自动管理,并且依赖于GC机制,能够自动识别和清理不用的内存空间,减少了手动释放内存的过程,简化的开发人员的工作。

下面我们就来谈谈Java自动内存所带来的OOM的问题。

什么是OOM?

Java中的OOM(Out of Memory)通常是指内存溢出异常,由于在Java程序运行的过程中,需要为每个对象都分配一定的内存空间。当一个应用程序因为某些原因需要使用更多的内存空间的时候,但是这个时候却无法分配到这些空间的时候,就会出现OOM的异常。

什么情况下会发生OOM?

一般情况下我们遇到的都是堆内存的溢出,因为在创建对象初期,大多数的对象都是占用堆内存空间,当堆内存分配不足的时候就会出现OOM的异常。

java.lang.OutOfMemoryError: Java heap space

堆内存溢出具体的场景有如下一些

简单举个例子,下面这段代码,如果一直运行,就会导致内存溢出

List<Integer> list = new ArrayList<>(); while (true) { list.add(1); }什么叫做内存泄露呢?

所谓的内存泄露,其实是与内存溢出不一样的一种特殊场景。其本质还是内存溢出,只不过是因为错误而导致的内存溢出,是指在程序运行的过程中,由于某些原因导致无法释放不再被使用的内存而导致内存占用不断增加而耗尽资源的一种情况。

常见的内存泄露的情况有如下几种

如下代码所示,就是一个典型的长周期对象持有了短周期对象的引用导致了内存泄露的问题。

List<Integer> list2 = new ArrayList<>(); @GetMapping("/headOOM2") public String headOOM2() throws InterruptedException { while (true) { list2.add(1); } }栈内存溢出

我们知道JVM的内存模型中,除了堆内存,还有一块栈内存,那么什么情况下会导致栈内存溢出呢?一般情况下发生栈内存溢出会抛出StackOverflowError的异常。

我们知道栈这种数据结构有个特点就是先进后出,那么基于这个特点,最有可能导致栈内存溢出的场景就是在调用递归方法的时候,递归的深度太深,导致方法栈内存不够,无法容纳方法的递归调用,就会导致栈内存溢出。

public class OOMExample { public static void recursiveMethod() { recursiveMethod(); } public static void main(String[] args) { recursiveMethod(); } }元空间耗尽

字符常量过多怎么解决,常见的字符常量怎么判断(2)

在Java8之前,JVM内存模型中还有一块内存叫做永久代。在Java8之后被元空间所取代了,而这块元空间主要的作用就是用来存储类的结构信息、方法信息、静态变量以及一些编译之后的代码等信息。

在Java8之前,对于一些大对象的内存分配,如果在堆内存中无法进行分配了,有一个概念就是内存管理会将这个对象的内存分配直接分配到永久代。如果说程序中出现了这种大量的大对象的分配,则会导致永久代的内存溢出。

显然这里元空间是取代了永久代的地位,它所完成的使命就是永久代的使命,所以当程序中加载了大量的类、以及动态生成的类、或者是使用了反射等操作生成了大量的大对象,最终就有可能导致元空间的内存被占满,导致内存溢出。

下面我们就来总结一下元空间被耗尽的情况。

根据上面所述,最终都是因为元空间是用来存储类信息的地方,如果类信息太多的话就会导致元空间内存溢出。如下的代码就是模拟了一个类加载太多导致元空间内存泄露的情况。

public class OOMExample { public static void main(String[] args) { while (true) { ClassLoader classLoader = new CustomClassLoader(); classLoader.loadClass("com.example.LargeClass"); } } }终极问题:如果一个Java线程处理请求的时候发生了内存溢出?那么整个进程还能处理请求么?

其实这个问题考察的内存还是挺多的。首先需要判断的就是OOM之后会不会导致整个的进程挂掉。其次呢?OOM是因为内存不够了?既然这样那么进程还能处理请求么?垃圾处理机制这个时候在干什么?难道不是因为垃圾处理之后发现无法清理了,没有空间了,最终的内存溢出是垃圾处理机制抛出的异常么?

带着这些问题我们来对其进行探究。

问题探究

首先做一个简单的分析。我们知道当程序发生了内存溢出的时候,我们观察到的情况是程序还在运行着,也就是说好像有些功能还能用,真的是这样么?

字符常量过多怎么解决,常见的字符常量怎么判断(3)

我们在执行一个方法的时候,该方法对应的线程如果发生了OOM的异常,到底其他线程能不能再进程中执行其实是取决于这些线程执行逻辑所使用的内存是否会继续大量的占用内存空间。如果这个线程对应使用的内存空间较小,内存可以提供的时候,那么这个线程就会正常的得到执行,并且在内存不足的时候也会抛出OOM异常。那么如果这个线程执行所使用的内存空间太大的话,就会直接触发OOM的异常。

那么在不发生内存溢出的情况下,为什么频繁的创建对象会导致OOM,GC不会将这些对象进行回收么?

总结

根据上面的分析讲解,相信大家对于问题也有了自己的认识,并且通过简单的分析我们得到了一个结论

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.