Java 内存优化笔记

(一) 查询数据库没有关闭游标

程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。我觉得可以这样做:

Cursor c = sqliteDb.query(TABLE_WORDS, word_full_projection,selection, null, null, null, null);
int numRows = c.getCount();
if(numRows > 0){
c.moveToFirst();
wordProfile account = new wordProfile();
account.createFromDb(c);
c.close();
return account;
}
c.close();

可以采取将cursor里的值赋值给实现Parcelable的类的成员变量,在所需要的地方相应取值便是,这样编可以做到及时关闭游标,释放资源。

(二) 构造Adapter时,没有使用缓存的 convertView

以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:

public View getView(int position, View convertView, ViewGroup parent)

来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参 View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。

由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。ListView回收list item的view对象的过程可以查看:

android.widget.AbsListView.java –> void addScrapView(View scrap) 方法

(三) Bitmap对象不在使用时调用recycle()释放内存

有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。

(四) 将变量的作用域设置为最小

最小化作用域意味着对垃圾收集器更快的可见。让我们举一个例子。我们有一个变量定义在方法级,当方法执行完毕后,也就是说,控制跳出方法后,则该变量将不会被引用。这也就意味着它已经可以被垃圾回收。但是如果该变量是类级的,这时垃圾回收器就需要等待直到对该类的所有的引用都被

移除后才能进行垃圾回收。优化属性的作用域是必须的。同样这也是封装原则。最小化作用域降低了通过包访问变量并减少了耦合。

(五) 仅当你确实需要时才初始化

这个的意思是在你确实需要使用对象之前才分配内存。有些时候,需要在方法的开头定义一些属性。当定义这些属性时,我们很可能在定义它们的时候对其进行初始化。 这种情况下,    如果在首次使用之前出现任何问题    (如出现异常),那么已经初始化的变量所占用的内存就被浪费了。

(六) 不要在循环中定义变量

这是大部分内存溢出的程序中的另一个常见的错误。在循环中定义和初始化变量,对于循环的每次执行,该变量实例将在内存中创建并分配内存。在循环启动后,第一个对象已经可以回收了。这种额外的内存分配也会增加垃圾回收器的负担。看一下下面的代码片段你将很容易的找出问题所在。有些时候,

确实有必要在循环内定义变量,不过一定要小心使用。

import java.util.Vector;
public class DeclareInLoopExample {
public void getDataIncorrect() throws Exception {
Vector data = new Vector(11);
for (String str : data) {
String newStr = “”;
// …Some string operations
newStr = newStr + “X” + “X”;
}
}
public void getDataCorrect() throws Exception {
Vector data = new Vector(11);
String newStr = “”;
for (String str : data) {
// …Some string operations
newStr = newStr + “X” + “X”;
}
}
}

(七) 不要在循环中定义变量

这是和 String 相关的一些东西,所有对 String 进行的操作都将产生另一个 String 对象。通常我们使用的 String 链接操作,这个需要注意,它会导致一个很长的动态的查询或产生一个 toString 方法中的 String。如果我们使用+操作符来连接字符串,这些额外的对象将根据+产生。当有过多操作的时候会变成很大的开销。使用不是不变对象,如 StringBuffer 来进行字符串链接操作。

(八) 不要在循环中定义变量

这会使得垃圾回收器的工作变得比较容易。 将重对象的引用设置为 null。这将释放对中对象的引用,使得垃圾回收器能立即释放它们占用的内存。

(九) 简单的使用 finally 块

finally 块即使 try 或 catch 执行不成功的时候也会执行,也就是说即使在 try 或 catch 中出现了任何异常,finally 块中的语句绝对也会执行。将清理内存的语句放在这里以保证内存被清理。

(十) 分散对象创建或删除的时间

集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增 加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机 会。

转载于:https://my.oschina.net/chenzebin/blog/158473

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值