java--GC原理分析与内存泄漏
java使用的垃圾回收算法是根路径搜索算法,在介绍改算法前先说说引用计数算法:
1 引用计数算法原理:给一个对象添加一个引用计数器,每当有一个地方引用他时,计数器加1;当引用失效时,计数器减1;任何时刻引用计数为0的对象就是不可能再被使用的,就会被回收。但是它的缺点就是很难解决对象之间相互循环引用的问题。所有java并没有采用该算法。
2 根路径搜索算法原理:通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(用图论的话说就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的,被判定为可回收对象。
可用作为GC Roots的对象有下面几种:
(1)虚拟机栈中引用的对象(栈的本地变量表);
(2)方法区中的类静态属性引用对象;
(3)方法区中常量应用对象;
(4)本地方法中JNI引用的对象;
内存泄漏:
1 含义:对象不可达,即在有向图中,存在通路与之相连;对象是无用的,即程序不会再使用这些对象。如果满足上面的两个条件,就会出现内存泄漏。
2 原因有几种:
(1)静态集合类引起内存泄漏
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。
(2)当集合里面的对象属性被修改后,再调用remove()方法时不起作用。
(3)监听器
在释放对象的时候却没有去删除这些监听器,增加了内存泄漏的机会。
(4)各种连接
比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。
(5)内部类和外部模块的引用
内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如: public void registerMsg(Object b); 这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。
(6)单例模式
不正确使用单例模式是引起内存泄漏的一个常见问题,单例对象在初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收,导致内存泄漏。