1.什么是内存泄露
内存泄露的定义:对象已经没有被应用程序使用,但是垃圾回收器没有办法移除它们,因为还在引用着。简而言之,对象是可达的但是不再使用。
我们可以看一下下面的图方便我们理解。
上面图中可以看出,里面有被引用对象和未被引用对象。未被引用对象会被垃圾回收器回收,而被引用的对象却不会。未被引用的对象当然是不再被使用的对象,因为没有对象再引用它。然而无用对象却不全是未被引用对象。其中还有被引用的。就是这种情况导致了内存泄漏。
2.为什么会发生内存泄露
我们来看看下面的例子,就会知道为什么会发生内存泄露。
A对象引用B对象,A对象的生命周期(t1-t4)比B对象的生命周期(t2-t3)长的多。当B对象没有被应用程序使用之后,A对象仍然在引用着B对象。这样,垃圾回收器就没办法把B对象从内存中移除,从而导致内存问题,因为如果A引用更多这样的对象,将会有更多的未使用对象存在,并且消耗内存空间。
B对象也可能会持有很多其他对象,这些对象同样也不会被垃圾回收器回收。所有的这些没在使用的对象将持续的消耗之前分配的内存空间。
3.常见的几种内存泄露的情况
(1)HashMap、ArrayList的集合对象他们经常会发生内存泄露,特别是当它们被声明为static时,它们的声明周期会变的和应用程序一样长。
(2)在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。
(3)比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。
4.实例
(1)JDK6中的substirng()方法容易导致内存泄漏。
String对象被当作一个char数组来存储,在String类中有3个域:char[] value、int offset、int count,分别用来存储真实的字符数组,数组的起始位置,String的字符数。由这3个变量就可以决定一个字符串。当substring方法被调用的时候,它会创建一个新的字符串,但是上述的char数组value仍然会使用原来父数组的那个value。父数组和子数组的唯一差别就是count和offset的值不一样。
详细参考:https://blog.youkuaiyun.com/zcxwww/article/details/51242401