三、Java的内存泄露
Java虽然由GC来回收内存,但也是存在泄露问题的,只是比C++小一点。
(1)与C++的比较
(2)Java内存泄露处理
例子:
List myList=new ArrayList();
for (int i=1;i<100; i++)
{
}
此时,所有的Object对象都没有被释放,因为变量myList引用这些对象。当myList后来不再用到,将之设为null,释放所有它引用的对象。之后GC便会回收这些对象占用的内存。
(3)内存泄露检测
四、java程序设计中有关内存管理的经验
1. 最基本的建议是尽早释放无用对象的引用。如:...
A a = new A();
//应用a对象
a = null; //当使用对象a之后主动将其设置为空
….
注:如果a 是方法的返回值,不要做这样的处理,否则你从该方法中得到的返回值永远为空,而且这种错误不易被发现、排除
2. 尽量少用finalize函数。它会加大GC的工作量。
3. 注意集合数据类型,包括数组、树、图、链表等数据结构,这些数据结构对GC来说,回收更为复杂。
4. 尽量避免在类的默认构造器中创建、初始化大量的对象,防止在调用其自类的构造器时造成不必要的内
5. 尽量避免强制系统做垃圾内存的回收,增长系统做垃圾回收的最终时间
6. 尽量避免显式申请数组空间
7. 别用new Boolean()
在很多场景中Boolean类型是必须的,比如JDBC中boolean类型的set与get都是通过Boolean封装传递的,大部分ORM也是用Boolean来封装boolean类型的,比如:
ps.setBoolean("isClosed",new Boolean(true));
ps.setBoolean("isClosed",new Boolean(isClosed));
ps.setBoolean("isClosed",new Boolean(i==3));
通常这些系统中构造的Boolean实例的个数是相当多的,所以系统中充满了大量Boolean实例小对象,这是相当消耗内存的。Boolean类实际上只要两个实例就够了,一个true的实例,一个false的实例。
Boolean类提供两了个静态变量:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
需要的时候只要取这两个变量就可以了,
比如:ps.setBoolean("isClosed",Boolean.TRUE);
那么象2、3句那样要根据一个boolean变量来创建一个Boolean怎么办呢?可以使用Boolean提供的静态方法:Boolean.valueOf()
比如:
ps.setBoolean("isClosed",Boolean.valueOf(isClosed));
ps.setBoolean("isClosed",Boolean.valueOf(i==3));
因为valueOf的内部实现是:return (b ? TRUE : FALSE);
所以可以节省大量内存。相信如果Java规范直接把Boolean的构造函数规定成private,就再也不会出现这种情况了。
8. 别用new Integer
9. 不要用StringBuffer代替字符串相加
10. 不要过滥使用哈希表
有一定开发经验的开发人员经常会使用hash表(hash表在JDK中的一个实现就是HashMap)来缓存一些数据,从而提高系统的运行速度。比如使用HashMap缓存一些物料信息、人员信息等基础资料,这在提高系统速度的同时也加大了系统的内存占用,特别是当缓存的资料比较多的时候。其实我们可以使用操作系统中的缓存的概念来解决这个问题,也就是给被缓存的分配一个一定大小的缓存容器,按照一定的算法淘汰不需要继续缓存的对象,这样一方面会因为进行了对象缓存而提高了系统的运行效率,同时由于缓存容器不是无限制扩大,从而也减少了系统的内存占用。现在有很多开源的缓存实现项目,比如ehcache、oscache等,这些项目都实现了FIFO、MRU等常见的缓存算法。
11. 避免过深的类层次结构和过深的方法调用。因为这两者都是非常占用内存的(特别是方法调用更是堆栈空间的消耗大户)。
12. 变量只有在用到它的时候才定义和实例化。
13. 共享静态存储空间