JAVA内存溢出和内存泄漏

来源:互联网 发布:airserver windows 编辑:程序博客网 时间:2024/06/06 00:18

基本概念

内存泄漏:只程序中动态分配内存给一些临时对象,但对象不会被GC收回,始终占用内存,使得程序始终无法使用这段内存。
内存溢出:程序运行过程中无法申请到足够的内存而导致的错误,内存溢出通常发生在old段和Permgem段GC后仍然无新内存空间容纳新的java对象的情况。

内存泄漏是内存溢出的一种诱因,不是唯一因素。

内存泄漏的几种场景

  1. 长生命周期的对象持有短生命周期对象的引用

    这是内存泄漏中最常见的场景,也是代码设计中经常出现的问题。例如,在全局静态map中缓存局部变量,且没有清空操作,随着时间的推移,这个map会越来越大,造成内存泄漏。
  2. 修改hashset中对象的属性,且参数是参与计算哈希值的属性

    当一个对象呗存储进HashSet集合中以后,就不能修改这个对象中那些**参与计算哈希值的属性**,否则对象修改后的哈希值与最初存储进HashSet集合汇总时的哈希值就不同了,这种情况下,即使使用该对象的当前引用作为参数去HashSet集合中检索对象,也将返回找不到对象的结果,导致无法从HashSet集合中删除当前对象,造成内存泄漏。
  3. 机器的连接数和关闭时间设置

    长时间开启非常耗费资源的连接,也会造成内存泄漏。

内存溢出的几种情况

  1. 堆内存溢出(OutOfMemoryError:java heap space)
    在JVM中,堆内存是用来存储对象实例和数组的。
    堆内存可以细分为Young Generation(年轻代)、Old Generation(年老代)以及Perm Generation(永久代)。其中Young Generation又可以分为Eden、From和To,From和To统称为Survivor Space。当生成新对象时,内存的申请过程如下:
    a、 JVM先尝试在eden区分配新建对象所需的内存;
    b、如果eden区内存足够,申请结束,否则下一步;
    c、JVM启动youngGC,试图将eden区中不活跃的对象释放掉,释放后若eden空间仍不足以放入新对象,则试图将部分eden中活跃对象放入survivor区;
    d、survivor区用作eden和old的中间交换区,当old区空间足够,survivor去中的对象会被移动到old区,否则保留在survivor区;
    e、当old区空间不足时,JVM会在old区进行full GC;
    f、full GC后,若survivor及old区仍然无法存放将eden复制过来的部分对象,导致JVM无法再eden区为新对象创建内存区域,则出现outOfMemoryError。

    对于堆内存溢出,主要注意大量的字符串拼接操作和循环中重复创建对象的问题,修改Java虚拟机中的Xms(初始堆大小)和Xmx(最大堆大小)参数可修改堆内存大小。

  2. 永久区内存溢出(OutOfMemoryError:permgem space)

    在jvm中,永久区主要存放的是类信息、常量、静态变量等。
    如果程序加载的类过多,或者使用反射、gclib等这种动态代理生成类的技术,就可能导致该区发生内存溢出,错误信息为:outOfMemoryError:permgem space
    解决方法有两种,

    1. 增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,分别表示初始永久区内存大小和最大永久区内存大小。
  3. 栈内存溢出(java.lang.StackOveFflowError)

    栈内存中存储的是与方法相关的环境变量,是线程独有的一块内存结构,栈内存发生问题必定是某个线程运行时产生了错误,一般是由于递归太深或方法调用层级过多导致的。

参考http://wade6.iteye.com/blog/1842907

0 0
原创粉丝点击