您的位置:首页 > 编程语言 > Java开发

Java内存溢出与内存泄漏

2016-03-16 22:14 246 查看
内存溢出:内存溢出就是指在指定大小的内存空间,写入了超出大小的数据(越界).或者没有足够的内存,供程序分配。

内存泄漏:程序在运行过程中动态申请的内存空间不再使用后没有及时释放,从而很可能导致应用程序内存无线增长。更广义的内存泄露包括未对系统的资源的及时释放,比如句柄等。

结果: 1.内存溢出:程序将停止

      2.内存泄漏:程序不会停止但是效率会降低,内存泄漏过多也可能造成内存溢出。

Java 内存泄漏:

发生情况及解决方法:

  1.静态集合类,如HashMap 和Vector

            静态集合类的生命周期和程序一致,一次集合对象不用时应及时将其设为Null。

  2.各种连接,如数据库连接,网络连接,I/O连接。

            连接不用时应将其Close,否则GC不会回收相应的对象。

  3.监听器。

            在释放对象时,必须删除相应的监听器。

  4.变量的不合理作用于。若对象仅在局部使用,却被声明在更大的作用范围当中,就可能造成内存泄漏,或者没有及时的将对象设为null,也会造成内存泄漏。

            对象声明,应该和其使用范围一致,并且使用结束后及时设为Null。

避免方法:

         1) 尽早释放无用对象的引用。

          好的办法是使用临时变量的时候,让引用变量在退出活动域后自动设置为null,暗示垃圾收集器来收集该对象,防止发生内存泄露。

          2) 程序进行字符串处理时,尽量避免使用String,而应使用StringBuffer。

          因为每一个String对象都会独立占用内存一块区域,如:

         3) 尽量少用静态变量。

         因为静态变量是全局的,GC不会回收。

         4) 避免集中创建对象尤其是大对象,如果可以的话尽量使用流操作。

          JVM会突然需要大量内存,这时会触发GC优化系统内存环境; 

         5) 尽量运用对象池技术以提高系统性能。

          生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

         6) 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。

 

          可以适当的使用hashtable,vector 创建一组对象容器,然后从容器中去取那些对象,而不用每次new之后又丢弃。

         7) 优化配置

Java 内存溢出:

     

区域  1.堆内存溢出  java.lang.OutOfMemoryError:Java heap space

      2.栈溢出

      3.方法区(包括常量池)溢出  java.lang.OutOfMemoryError: PermGen space 加载了过多的类,jar等

      4.直接内存溢出

 

情况:1、在程序中存在死循环,或者循环过多,而产生了过多重复的对象的实例;

     2、存在对象的引用,使用完后没有清除,导致JAVA虚拟机不能回收;如集合的使用。

     3、一次操作时,在内存中加载了大量的数据;(算法空间复杂度过高) 

     4.使用的第三方软件中的BUG; 

     5.启动参数内存值设定的过小;

原则上来说,在JAVA中,由于它的自动垃圾回收机制,出现内存溢出的可能性并不是很大。

排查:

    1.检查代码中是否有死循环或递归调用。 

    2.检查是否有大循环重复产生新对象实体。 

    3.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。 

    4.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。 

解决:  1.从代码层面进行优化完善,尽量避免该情况发生;

          一:

            1.对那些静态(static)的对象要特别留神,特别是类型为Map,List,Set的,静态的变量会一直驻存在内存中,生命周期比较长,不会被垃圾器回收。

            2.对于代码,要审查是否生成了大量的冗余的对象,还有一些逻辑业务处理的类,

          算法是否过于复杂,调整算法,对于代码认真审查,再仔细重构一遍代码,能提高代码质量,提高程序运行稳定性。

           

          3.Java中的内存溢出大都是因为栈中的变量太多了。其实内存有的是。建议不用的尽量设成null以便回收,多用局部变量,少用成员变量。

          4.在我的程序中对静态变量的优化后,使程序占用内存量至少提升了5k-10k。所以也不容忽视。

          二:

            还有就是String类相关的东西:

          1.字符串累加的时候一定要用StringBuffer的append方法,不要使用+操作符连接两个字符串。差别很大。而且在循环或某些重复执行的动作中不要去创建String对象,因为String对象是要用StringBuffer对象来处理的,一个String对象应该是产生了 3个对象(大概是这样:))。

          2.字符串length()方法来取得字符串长度的时候不要把length放到循环中,可以在循环外面对其取值。(包括vector的size方法)。特别是循环次数多的时候,尽量把length放到循环外面。

             3 写代码的时候处理内存溢出   

                   try{   

                      //do   sth    

                   }catch   (outofmemoryerror   e){//可以用一个共通函数来执行.   

                    system.out.print   (“no   memory!   ”);   

                    system.gc();   

                     //do   sth   again   

                  ....   

                   }          

             4.对于频繁申请内存和释放内存的操作,还是自己控制一下比较好,但是System.gc()的方法不一定适用,最好使用finallize强制执行或者写自己的finallize方法。 Java 中并不保证每次调用该方法就一定能够启动垃圾收集,它只不过会向JVM发出这样一个申请,到底是否真正执行垃圾收集,一切都是个未知数。

       2.调整优化JVM,服务器配置(调整参数): 

         1) 设置-Xms、-Xmx相等;

         2) 设置NewSize、MaxNewSize相等;

         3) 设置Heap size, PermGen space(永久代空间)

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: