最近系统在导出到excel的时候总出现内存溢出。特研究下,大部分程序员写代码的时候都不会考虑一下细节:
1、不要对同一个对象初始化多次.例如:
public class A{
private ArrayList list= new ArrayList ();
public A(){
list= = new ArrayList (); // 这里应该去掉,因为list= 已经被初始化.
}
2、处理Java的内存泄露问题:确认该对象不再会被使用,接着典型的做法——把对象数据成员设为null
注意,当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。
例子:
List myList=new ArrayList();
for (int i=1;i<100; i++)
{
Object o=new Object();
myList.add(o);
o=null; //没必要
}
此时,所有的Object对象都没有被释放,因为变量myList引用这些对象。正确的做法:当myList后来不再用到,将之设为null,释放所有它引用的对象。
3、用StringBuffer代替字符串相加 :String一旦赋值或实例化后就不可更改,如果赋予新值将会重新开辟内存地址进行存储。
而StringBuffer类使用append和insert等方法改变字符串值时只是在原有对象存储的内存地址上进行连续操作,减少了资源的开销。
4、变量只有在用到它的时候才定义和实例化。(类似1)
5、别用new Integer。JDK中对Integer的实例化进行了优化,Integer类缓存了-128到127这些值的Integer,如果使用Integer.valueOf(int i),传入的int范围正好在此内,就返回静态实例。这样如果我们使用Integer.valueOf代替new Integer的话也将大大降低内存的占用。
其他类型同理。
6、用不到字段不要查询出来。
select t.* from table t 和 select t.c1,t.c2 from table的区别,主要体现在数据的传输量。查询的字段多少跟数据量是成正比的,特别是中国的网络状况并不让人满意,如果你只用到了c1和c2两个字段,就按第二种写法吧。你也许会说,我的项目部署在局域网中,传输速度很快。即便如此,查询之后封装到对象中,全部字段都查出来和查询所需的字段,占用内存也是跟字段数成正比的。
当然,还有很多优化内存占用的办法,先写这么多。如果做到了以上几点,相信内存溢出的几率会减少很多。
附查看内存占用的代码:
long memory = Runtime.getRuntime().totalMemory()
- Runtime.getRuntime().freeMemory();
System.out.println(String.format("%.1f MB",
(memory / (1024.0 * 1024.0))));