首页编程java编程java oom异常是什么,java oom异常怎么解决方案

java oom异常是什么,java oom异常怎么解决方案

编程之家2023-10-1288次浏览

大家好,感谢邀请,今天来为大家分享一下java oom异常是什么的问题,以及和java oom异常怎么解决方案的一些困惑,大家要是还不太明白的话,也没有关系,因为接下来将为大家分享,希望可以帮助到大家,解决大家的问题,下面就开始吧!

java oom异常是什么,java oom异常怎么解决方案

java outofmemory

java outofmemory是什么,让我们一起了解一下?

out of memory(内存溢出)是一个程序员常见的错误类型,通常是开启应用程序过多所导致。一般是由于电脑内存不足,配置过低,电脑开启的应用程序过多,导致内存不足或者游戏客户端的问题。

java oom异常是什么,java oom异常怎么解决方案

Java中OutOfMemoryError(内存溢出)出现的情况和解决办法是什么?

java oom异常是什么,java oom异常怎么解决方案

第一种OutOfMemoryError: PermGenspace。

发生这种问题的原意是程序中使用了大量的jar或class,使java虚拟机装载类的空间不够,与PermanentGeneration space有关。解决这类问题有以下两种办法: 

1、增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。如针对tomcat6.0,在catalina.sh或catalina.bat文件中一系列环境变量名说明结束处(大约在70行左右)增加一行: 

JAVA_OPTS="-XX:PermSize=64M-XX:MaxPermSize=128m"。

如果是windows服务器还可以在系统环境变量中设置。感觉用tomcat发布sprint+struts+hibernate架构的程序时很容易发生这种内存溢出错误。

2、清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。这种方法是网上部分人推荐的,我没试过,但感觉减少不了太大的空间,最靠谱的还是第一种方法。 

第二种OutOfMemoryError: Java heap space 。

发生这种问题的原因是java虚拟机创建的对象太多,在进行垃圾回收之间,虚拟机分配的到堆内存空间已经用满了,与Heapspace有关。解决这类问题有两种思路: 

1、检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改程序和算法。 

写一个使用K-Means文本聚类算法对几万条文本记录(每条记录的特征向量大约10来个)进行文本聚类时,由于程序细节上有问题,就导致了Javaheap space的内存溢出问题,后来通过修改程序得到了解决。 

2、增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。如:set JAVA_OPTS=-Xms256m-Xmx1024m。

实战操作,本机内存溢出代码如下: package DirectMemory; import sun.misc.Unsafe; import java.lang.reflect.Field;/** * VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M * DirectByteBuffer分配内存也会抛出内存溢出异常,但它抛出异常时没有真正向系统申请分配内存,而是通过计算得知内存 * 无法分配,于是手动抛出异常。有点类似操作系统的银行家算法(避免死锁) */ public class DirectMemoryOOM {    private static final int _1MB = 1024*1024;    public static void main(String[] args) throws IllegalAccessException {        Field unsafeField = Unsafe.class.getDeclaredFields()[0];        //获取类中第一个变量        unsafeField.setAccessible(true);                               //设置是否可反射访问private变量        Unsafe unsafe = (Unsafe) unsafeField.get(null);             //获取静态对象        while (true){            unsafe.allocateMemory(_1MB);                            //申请分配内存        }    }}

Java垃圾回收:GC在什么时候对什么做了什么

GC在什么时候对什么做了什么?

要回答这个问题,先了解下GC的发展史、jvm运行时数据区的划分、jvm内存分配策略、jvm垃圾收集算法等知识。

先说下jvm运行时数据的划分,粗暴的分可以分为堆区(Heap)和栈区(Stack),但jvm的分法实际上比这复杂得多,大概分为下面几块:

1、程序计数器(Program Conuter Register)

程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工作器就是通过改变这个计数器的值来选取下一条需要执行的指令。它是线程私有的内存,也是唯一一个没有OOM异常的区域。

2、Java虚拟机栈区(Java Virtual Machine Stacks)

也就是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候都创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等。每个方法被调用到完成,相当于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:如果线程请求的栈深度大于虚拟机允许的深度将抛出StackOverflowError;如果虚拟机栈可以动态的扩展,扩展到无法动态的申请到足够的内存时会抛出OOM异常。

3、本地方法栈(Native Method Stacks)

本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。

4、堆区(Heap)

所有对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为所有线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。

5、方法区(Method Area)

方法区也是所有线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时抛出OOM异常。

6、运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。

垃圾收集(Garbage Collection)并不是Java独有的,最早是出现在Lisp语言中,它做的事就是自动管理内存,也就是下面三个问题:

1、什么时候回收

2、哪些内存需要回收

3、如何回收

1、什么时候回收?

上面说到GC经常发生的区域是堆区,堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。

1.1对象优先在Eden中分配,当Eden中没有足够空间时,虚拟机将发生一次Minor GC,因为Java大多数对象都是朝生夕灭,所以Minor GC非常频繁,而且速度也很快;

1.2 Full GC,发生在老年代的GC,当老年代没有足够的空间时即发生Full GC,发生Full GC一般都会有一次Minor GC。大对象直接进入老年代,如很长的字符串数组,虚拟机提供一个-XX:PretenureSizeThreadhold参数,令大于这个参数值的对象直接在老年代中分配,避免在Eden区和两个Survivor区发生大量的内存拷贝;

1.3发生Minor GC时,虚拟机会检测之前每次晋升到老年代的平均大小是否大于老年代的剩余空间大小,如果大于,则进行一次Full GC,如果小于,则查看HandlePromotionFailure设置是否允许担保失败,如果允许,那只会进行一次Minor GC,如果不允许,则改为进行一次Full GC。

2、哪些内存需要回收

jvm对不可用的对象进行回收,哪些对象是可用的,哪些是不可用的?Java并不是采用引用计数算法来判定对象是否可用,而是采用根搜索算法(GC Root Tracing),当一个对象到GC Roots没有任何引用相连接,用图论的来说就是从GC Roots到这个对象不可达,则证明此对象是不可用的,说明此对象可以被GC。对于这些不可达对象,也不是一下子就被GC,而是至少要经历两次标记过程:如果对象在进行根搜索算法后发现没有与GC Roots相连接的引用链,那它将会第一次标记并且进行一次筛选,筛选条件是此对象有没有必要执行finalize()方法,当对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用执行过一次,这两种情况都被视为没有必要执行finalize()方法,对于没有必要执行finalize()方法的将会被GC,对于有必要有必要执行的,对象在finalize()方法中可能会自救,也就是重新与引用链上的任何一个对象建立关联即可。

3、如何回收

选择不同的垃圾收集器,所使用的收集算法也不同。

在新生代中,每次垃圾收集都发现有大批对象死去,只有少量存活,则使用复制算法,新生代内存被分为一个较大的Eden区和两个较小的Survivor区,每次只使用Eden区和一个Survivor区,当回收时将Eden区和Survivor还存活着的对象一次性的拷贝到另一个Survivor区上,最后清理掉Eden区和刚才使用过的Survivor区,Eden和Survivor的默认比例是8:1,可以使用-XX:SurvivorRatio来设置该比例。

而老年代中对象存活率高,没有额外的空间对它进行分配担保,必须使用“标记-清理”或“标记-整理”算法。

java oom异常怎么解决方案

在 Java中,JavaVM拥有自动管理内存的功能,Java的GC能够进行垃圾回收,但是Android中如果ImageView使用过多的Bitmap的话,经常会报OOM(内存溢出)。

造成内存溢出及解决方案:

1.使用BitmapFactory.decodeStream替代createBitmap方法

原因是该方法直读取图片字节,调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap。

2.使用压缩读取技术

BitmapFactory.Options options= new BitmapFactory.Options();

options.inJustDecodeBounds= true;

BitmapFactory.decodeFile(imageSdUri, options);

final int height= options.outHeight;

final int width= options.outWidth;

options.inSampleSize= 1;

int w= 320;

int h= 480;

h= w*height/width;//计算出宽高等比率

int a= options.outWidth/ w;

int b= options.outHeight/ h;

options.inSampleSize= Math.max(a, b);

options.inJustDecodeBounds= false;

Bitmap bitmap= BitmapFactory.decodeFile(imageSdUri, options);

3.及时释放Bitamp

Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null.虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。但是我它应该还是能大大的加速Bitmap的主要内存的释放。

关于java oom异常是什么的内容到此结束,希望对大家有所帮助。

java判断是什么异常?Java:如何判断异常种类呢现在只知道是Exception ejava模板什么意思,JAVA中文是什么意思