内存泄露与内存溢出

一、什么是内存泄露

内存泄露是指一个不在被程序使用的对象或变量还在内存中占有存储空间。

1. 内存泄露主要有两种情况:

       (1). 在堆中申请的空间没有释放

       (2.) 该对象已经不再使用,却还在内存中保留着

一般垃圾回收机制可以有效的解决第一种情况。

Java内存泄露主要是第二种情况。

1 Vector v = new Vector();
2 for ( int i=0 ;i<10; i++ ){
3     Object o = new Object();
4     v.add(o);
5 }

在循环中不断创建对象加入到Vector对象中,退出循环后o的作用域将会结束,

在v中使用这些对象,垃圾回收器无法回收,造成内存泄露。只有将这些对象从

vector中删除才能释放这些对象。

2. 泄露原因

(1)静态集合类。例如 HashMap 和 Vector 。如果这些容器为静态的static,他们

的生命周期和程序一致,那么容器中的对象在程序结束之前不能被释放,从而造成

内存泄露。也就是长生命周期对象持有短生命周期的对象。

(2)各种连接。如数据库连接、IO连接、网络连接等。需要先建立连接,不使用时

要使用 close() 释放连接,只有关闭连接后垃圾回收器才会回收对应的对象,否则会

有大量对象无法回收二造成内存泄露。

(3)监听器。通常一个应用中用到多个监听器,当释放对象时,往往没有删除相应

的监听器,而造成内存泄露。

(4)变量作用域不合理。如果一个变量的作用域大于其使用的范围,可能会造成内

存泄露。如:

1 Class Server{
2      private String msg;
3      public void receiveMsg(){
4          readFromNet();//从网络中接收msg
5          saveDB();//保存msg到数据库
6     }
7 }

从网络中接收msg然后保存到数据库之后msg就没用了,但是msg生命周期和对象的

生命周期相同,所以不会立刻被回收,造成内存泄露。

(5)单例模式可能会造成内存泄露。

 1 public class BigClass{
 2   //code
 3 }
 4 public class Singleton {
 5     private Singleton(BigClass bc){
 6         this.bc = bc;
 7     }
 8     private BigClass bc;
 9     private static Singleton instance = new Singleton(new BigClass());
10     public Singleton getInstance(){
11         return instance;
12     }
13 }

单例模式Singleton存在一个对对象 bc 的引用,但是单例instance对象以静态方式存储,它

在JVM整个生命周期都存在,bc无法被回收,导致内存泄露。

3. 内存泄露的解决方案:

(1)避免在循环中创建对象

(2)最早释放无用对象

(3)尽量少用静态变量,因为静态变量在永久代,很少参加垃圾回收。

(4)使用字符串处理避免使用String,而用StringBuffer。

4.如何查找内存泄露

使用Jconsole。

二、什么是内存溢出

指的是程序运行过程中无法申请到足够的内存空间而导致的一种错误。

1. 内存溢出的几种情况:

除了程序计数器外,虚拟机其他几个运行时区域都可能发生OutOfMemorryError(OOM)异常。

(1)虚拟机栈和本地方法栈溢出

  如果线程请求的栈深度大于虚拟机所允许的最大深度, 将抛出
  StackOverflowError 异常。
  如果虚拟机在扩展栈时无法申请到足够的内存空间, 则抛出
  OutOfMemoryError 异常。

(2)堆溢出

  一般的异常信息:java.lang.OutOfMemoryError:Java heap spaces。

  检查虚拟机的参数(-Xmx 与-Xms)的设置是否适当

(3)方法区溢出
  异常信息:java.lang.OutOfMemoryError:PermGen space。
(4)运行时常量池溢出
  异常信息:java.lang.OutOfMemoryError:PermGen space。
  如果要向运行时常量池中添加内容, 最简单的做法就是使用
  String.intern()这个Native 方法。该方法的作用是:如果池中已经包含一个
  等于此String 的字符串,则返回代表池中这个字符串的String 对象;否则,
  将此String 对象包含的字符串添加到常量池中,并且返回此String 对象的引
  用。

 2. 内存溢出的原因

(1)内存中加载的数据过于庞大,如一次从数据库取出过多数据

(2)集合类中对对象的引用,使用完未清除,JVM无法回收

(3)代码中存在死循环或循环产生过多重复的对象实体

(4)启动参数内存值设置过小

3.内存溢出解决办法

(1)修改JVM启动参数,直接增加内存

一般要将-Xms 和-Xmx 选项设置为相同,以避免在每次GC 后调整堆的大小;建
议堆的最大值设置为可用内存的最大值的80%

(2)检查错误日志,查看 “outOfMemory” 错误前是否有其他异常或错误

(3)使用内存查看工具动态查看内存使用情况(Jconsole)。

扩展:
基本上如果抛出OutOfMemory 有两种原因:1.内存泄露。2.应用程序本身
就是需要这么多的内存。

原文地址:https://www.cnblogs.com/yumingxing/p/9482984.html