0
点赞
收藏
分享

微信扫一扫

Java基础-JVM-内存溢出与内存泄露

Java工程师知识树 / Java基础


内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

内存泄露memory leak会最终会导致内存溢出out of memory

内存溢出出现的场景

内存溢出原因为没有足够的内存空间供申请

堆内存溢出

java的堆中主要是用来存放数组和对象的相关的jvm属性配置为:-Xms -Xmx

堆内存溢出(outOfMemoryError:java heap space)主要指的是Java堆中没有足够的空间去容纳创建的对象所需要的内存大小。

比如当前堆的总内存为8G,可用内存为5G,程序中创建了一个100万对象List,需要10G,5G小于10G,内存空间不够,则内存溢出。

堆内存溢出的情况,主要如下:

  • 查询数据库时数据较多的表时,查询条件中能筛选绝大部分数据的条件为空,且未采用游标等查询优化方式,将数据全部读取放到内存中。因此需要很大的堆内存,然后溢出。
  • 程序中一些操作,需要占用不至于溢出,但也不算少的内存时(比如一个申请,将需要500M的内存,但是系统中一共5G内存),当有12个请求一起发送到系统时,将会占用6G左右的内存,5G<6G,内存溢出。
  • 程序死循环,无限创建变量

方法区内存溢出(JDK1.8之前版本)

java中的方法区主要用来存储类信息、常量、静态变量等。相关的jvm属性配置为:-XX:PermSize、-XX:MaxPermSize

方法区内存溢出(outOfMemoryError:permgem space)一般情况下不会出现,除非是加载类太多,或者java动态代理、CGLIB使用不当导致。

线程栈溢出

线程栈溢出(java.lang.StackOverflowError)主要指的是方法调用层级太多导致的溢出。

递归使用不当陷入死循环导致栈溢出。


导致内存泄漏的常见原因:

内存泄漏的原因为无法释放已申请的内存空间

  1. 循环过多或死循环,产生大量对象;
  2. 静态集合类引起内存泄漏,因为静态集合的生命周期和 JVM 一致,所以静态集合引用的对象不能被释放,集合类元素太多可能导致内存泄露;
  3. 单例模式,和静态集合导致内存泄露的原因类似,因为单例的静态特性,它的生命周期和 JVM 的生命周期一样长,所以如果单例对象如果持有外部对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄漏。
  4. 数据连接、IO、Socket连接等等,它们必须显示释放(用代码在finally里执行 close 代码),否则不会被 GC 回收。
  5. 内部类的对象被长期持有,那么内部类对象所属的外部类对象也不会被回收。
  6. Hash 值发生改变,比如下面中的这个类,它的 hashCode 会随着成员变量的变化而变化,每次成员变量变化后都会生成一个新对象:
    注:当我们想把自己定义的类保存到散列表的时候,需要保证对象的 hashCode 不可变。
  7. 内存中加载数据量过大;初始化加载的数据量占用内存超过设置的JVM参数值。
举报

相关推荐

0 条评论