Android杂谈--内存泄露(1)--contentView缓存使用与ListView优化-点点未来-天下标王
Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1089377
  • 博文数量: 403
  • 博客积分: 10272
  • 博客等级: 上将
  • 技术积分: 4407
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 14:22
文章分类

全部博文(403)

文章存档

2012年(403)

分类: 嵌入式

2012-04-10 19:24:23

引起Android内存泄露有很多种原因,下面罗列了一些问题,以后会一一解决

1、构造Adapter时没有使用缓存convertView(衍生出ListView优化问题)

2、查询数据库游标没有关闭

3、Activity中生命周期对象大于Activity生命周期(关于Application Context与Activity Context)

4、Bitmap对象不使用时没有recycle掉(这里还有其他解决方案)

 

今天说的是第一种:如何使用缓存来优化ListView

因为如果不使用缓存convertView的话,调用getView时每次都会重新创建View,这样之前的View可能还没有销毁,加之不断的新建View势必会造成内存泄露。

使用getView时有3方案:(1)没有使用convertView,(2)使用convertView,(3)使用convertView+静态类ViewHolder

 

我做了一个测试,代码在下面,创建2000个View,从0拉到最后,计算总共耗,同时显示GC释放内存的大小,三种测试的结果如下:

注:这里先说下 GC_EXTERNAL_ALLOC freed 7K, 18% free 11153K/13511K, external 1632K/1672K, paused 89ms 的意思

  在Dalvik中,为一个程序分配的内存要根据机型的不同而不同,一般为32M,而虚拟机会把这些内存分别分配给,JAVA使用的堆内存 (heap)和Nativie使用的内存(external)(即虚拟机中通过JNI调用本地Nativie的类中malloc分配的内存,如 Bitmap,java.nio.ByteBuffers)。不过两者不同共享,也就是说Native的内存不够用了,而JAVA内存够用时是不能向 JAVA申请的,必须向虚拟机申请才行,当虚拟机无法分配的时候就会报OOM的错误

freed 7k:表示GC已经释放了7K的内存

18% free 11153K/13511K:表示JAVA使用的堆内存(对象存在于此),18% free表示当前剩余18%的堆内存(heap memory),11153K表示当前已用的堆内存,13511K表示堆内存总共大小(网上有些文章这部分弄错了,很多转载都是同一个)

external 1632K/1672K:1632K表示已用external memory,总共1672K external memory(注意:这个可能只存在于Android 3.0之前)

paused 89ms:这里其实包括了两部分,一个是在调用GC之前暂停的时间,一个是调用GC后基本完成时暂停的时间

详细可参考:

 

(1)没有使用convertView

  没有任何处理,不建议这样写。如果数据量少可以,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性能,所以从一开始就不要用这种方式

@Override public View getView(int position, View convertView, ViewGroup parent) { //Get a View that displays the data at the specified position in the data set. //开始计时,性能测试用nanoTime会更精确,因为它是纳秒级的 long startTime = System.nanoTime(); View item = mInflater.inflate(R.layout.list_item, null); ImageView img = (ImageView)item.findViewById(R.id.img); TextView title = (TextView)item.findViewById(R.id.title); TextView info = (TextView)item.findViewById(R.id.info); img.setImageResource(R.drawable.ic_launcher); title.setText("loulijun"); info.setText("www.cnblogs.com/loulijun"); //停止计时 long endTime = System.nanoTime(); //耗时 long spendTime = (endTime - startTime); sumTime += spendTime; Log.d("GoogleIO", "position at:"+position+"--sumTime:"+String.valueOf(sumTime)); return item; }

测试结果:

目前VM只为他们分配了5767K+518k的内存,而内存峰值是32M

刚开始时,而且heap memory只申请了5767K,已用内存3353K,注意数据大小的变化:耗时:167633055ns = 0.167633055秒

当拉到1000的时候,堆内存总计已经申请了9607K,已用内存7245K,明显已经比刚开始时要大了 ,耗时:3435241667ns=3.435241667秒

当拉到2000的时候,堆内存总计13511K,已用内存11153K,耗时:6660369835ns = 6.660369835秒

---------------------------我又创建了10000个ListView,测试后直到内存泄露,证明峰值却是是32M,而 不使用convertView导致的内存泄露,当内存泄露时手机会提示force close,并将错误写入/data/anr/traces.txt中,你可以adb pull下来查看具体信息

(2)使用convertView后的测试数据(优化后)

  通过缓存convertView,convertView可以缓存可视范围内的convertView,当再次向下滑动时又开始更 新View,这种利用缓存convertView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,这样会 减少很多View的创建,提升了性能

 

@Override public View getView(int position, View convertView, ViewGroup parent) { //Get a View that displays the data at the specified position in the data set. if(convertView == null) { convertView = mInflater.inflate(R.layout.list_item, null); } //开始计时,性能测试用nanoTime会更精确,因为它是纳秒级的 long startTime = System.nanoTime(); ImageView img = (ImageView)convertView.findViewById(R.id.img); TextView title = (TextView)convertView.findViewById(R.id.title); TextView info = (TextView)convertView.findViewById(R.id.info); img.setImageResource(R.drawable.ic_launcher); title.setText("loulijun"); info.setText("www.cnblogs.com/loulijun"); //停止计时 long endTime = System.nanoTime(); //耗时 long spendTime = (endTime - startTime); sumTime += spendTime; Log.d("GoogleIO", "position at:"+position+"--sumTime:"+String.valueOf(sumTime)); return convertView; }

 

测试数据我还是用2000吧,10000太大了(一万年太久,只争朝夕)

测试结果:

这次一直拉到最后明显比刚才流畅多了,而且GC释放内存的次数也明显少了很多,最后用的时间和当前使用的内存也小很多,优化后的确好多了

当position为1000的时候,附近没怎么调用GC,用时:213653551ns=0.213653551秒,额,差距有点大,上面到达1000时用时达到3.43秒之多。

当position为2000的时候,已用内存只有3068K,堆总共内存6215K,而且external memory是0K,用时:378326396ns = 0.378326396秒,性能差距如此之大,都有点不敢相信。也不知道这种方式对不对,如有不妥的地方,还希望大牛能给出正确回答

(3)使用contentView+静态类ViewHolder类

  通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。

当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局 (XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些 控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。(看下 面代码中)

如果convertView不为空的时候,就会直接用convertView的getTag(),来获得一个ViewHolder。

静态类ViewHolder

//定义静态类ViewHolder static class ViewHolder { public ImageView img; public TextView title; public TextView info; }
@Override public View getView(int position, View convertView, ViewGroup parent) { //Get a View that displays the data at the specified position in the data set. //开始计时,性能测试用nanoTime会更精确,因为它是纳秒级的 long startTime = System.nanoTime(); ViewHolder holder; if(convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_item, null); holder.img = (ImageView)convertView.findViewById(R.id.img); holder.title = (TextView)convertView.findViewById(R.id.title); holder.info = (TextView)convertView.findViewById(R.id.info); convertView.setTag(holder); }else { holder = (ViewHolder)convertView.getTag(); holder.img.setImageResource(R.drawable.ic_launcher); holder.title.setText("loulijun"); holder.info.setText("www.cnblogs.com/loulijun"); } //停止计时 long endTime = System.nanoTime(); //耗时 long spendTime = (endTime - startTime); sumTime += spendTime; Log.d("GoogleIO", "position at:"+position+"--sumTime:"+String.valueOf(sumTime)); return convertView; }

到这里,可能会有人问ViewHolder静态类结合缓存convertView与直接使用convertView有什么区别吗,是否重复了

在这里,官方给出了解释

提升Adapter的两种方法

To work efficiently the adapter implemented here uses two techniques:
-It reuses the convertView passed to getView() to avoid inflating View when it is not necessary

(译:重用缓存convertView传递给getView()方法来避免填充不必要的视图)
-It uses the ViewHolder pattern to avoid calling findViewById() when it is not necessary

(译:使用ViewHolder模式来避免没有必要的调用findViewById():因为太多的findViewById也会影响性能)
ViewHolder类的作用
-The ViewHolder pattern consists in storing a data structure in the tag of the view
returned by getView().This data structures contains references to the views we want to bind data to,
thus avoiding calling to findViewById() every time getView() is invoked

(译:ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们

要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById())

 

测试数据:(跟直接使用convertView数据相差不多)

当position为1000时,用时:199188216ns = 0.199188216秒,堆内存的时候也没比没有使用convertView理想的多

当position为2000时,用时:336669887ns = 0.336669887秒,比直接使用convertView的方式稍微好一点点,不过性能相差不多

阅读(2353) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~

相关内容推荐

怎么优化网站的图片场口优化网站哪家公司好天津网站优化托管业务巩义外贸网站优化哪家靠谱张家港网站建设优化岳阳县网站seo优化排名云南网站优化seo优化网站询问火30星论坛收录后应该怎么优化网站网站的seo优化是什么日照电脑网站优化公司射阳网站seo优化优化公司网站立择火3星顶尖湘西网站搜索优化哪家好江南区网站seo优化排名节能设备网站seo优化咨询新力网站优化网站优化 h几 更易被抓深圳知名网站优化怎么做开平网站推广优化做网站优化的怎么电话邀约客户顺平县网站优化电子商务网站内链的优化保定网站搜索优化工具素材网站优化普定网站seo优化运城关键词网站优化郑州网站优化推广公司大同专业外贸网站seo优化茂名如何优化网站灞桥网站优化推广曲阜网站优化招商模板网站关键词优化惠城网站优化服务焦作网站建设优化渠道铜官区网站seo优化排名沈阳网站优化需要做什么网站优化需要懂的知识企石网站关键词优化公司泰安网站优化外包怎样优化网站同时多人登录更合网站优化入门如何优化网站优越易速达岑巩县网站优化服务永年公司网站优化蓟县网站优化推广宁海网站优化怎么选椒江网站优化公司网站内部优化包含哪几部分长宁区企业网站优化定制方案网站bc词怎么优化优化网站排名参谋易速达思域中控优化网站是真的假的下沙网站排名优化沙田网站seo优化哪儿好南京市优化网站推广哪里有卖东门网络营销网站优化南宁服务好网站推广优化网站首页seo优化设置网站优化分析技巧泉州网站优化如何网站图片如何优化大小德州高端网站优化公司网站URL结构优化实训报告沿滩区网站优化德惠优化网站域名与网站优化之间的关系怎样优化网站排名第一聊城网站优化如何如何优化网站云速捷出词快优化手机网站注意事项静安区官方网站优化机构全网推广网站优化哪家正规国内 海外服务器反代优化网站房山网站关键词排名优化深圳正规网站优化的主要方法机械设备网站优化运营网站优化需要重视什么佛山首页网站关键词优化教程椰果网站优化介休网站优化价格玉溪优化网站百度网站优化特点浙江网站优化推荐网站 优化趁便易速达广东怎么优化网站道滘网站优化哪些好外贸型网站seo优化效果张家港卓成网站好还是优化好上饶很好的网站优化用户体验linux优化社区论坛网站威海网站优化费用贵定县分类网站优化怎么免费优化自己的网站唐山网站搜索引擎优化优化网站方法12金手指霸屏在线网站优化注意什么优化网站排名差异餐饮行业网站优化全包服务网站优化联系方式永登县网站seo优化排名兰州网站权重优化团队政府网站在线办事优化长春市网站建设优化公司哪家好石峰优化网站聊城网站优化策略厦门网站seo优化怎么做网站优化进度表怎么做泰州seo优化的网站价格沈阳高端网站优化网站定制优化吗石狮市网站seo优化排名招商最好用的网站优化甘肃网站优化推广外包公司贾汪区网站优化网站推广排名SEO教程优化优化网站方法选择火27星要遵义seo网站优化怎样优化网站服务揭阳网站优化培训石碣服装网站优化哪些服务郑州搜索引擎网站优化网站优化的二十个术语项城网站自然优化价格表集团网站seo优化阳江铝型材网站seo优化宜宾网站制作优化服务扬州市优化网站推广如何优化模板网站空调网站的优化毕业设计如何优化门户网站乐平市网站优化网站优化价格陷阱邯郸网站seo如何优化费用龙岗公司的网站优化沈阳规模大的网站关键词优化网站建设优化企业站点石河子网站seo优化哪家好网站建设优化推广杭州某个网站的优化情况珠海网站优化对策张家港网站优化推广宁夏网站霸屏如何优化太原网站排名优化软件同安区网站优化推广为什么网站要优化宣传福永个人如何做网站优化东莞市承接网站seo怎么优化廊坊网站建设优化邢台网站优化效果网站标题优化怎么设置乐从网站优化价格表新乡企业网站优化电话天津企业网站关键词优化医院网站优化文章范文网站优化的作业及意义优化网站软件安乐易速达潜山pc网站优化平面优化学习网站长沙网站seo优化公司网站维护 优化企业网站seo优化有什么好处曲沃县网站seo优化排名景洪怎么做网站优化网站推广 优化是什么意思网站排名优化 都看宙斯可以搜索引擎网站优化费用汝州网站优化排名北京知名网站优化费用专业seo网站排名优化网站排名优化咨询金手指信用滕州刷联网站建设优化焦作网站关键词优化软件永登县网站seo优化排名临沂网站优化哪有怎么在网站优化哪里好网站优化推广哪家价格实惠迁安网站关键词优化成都公司网站优化吉林网站排名如何优化网站优化需要什么技能怎样给网站做优化公司策划网站优化方案基本流程网站seo优化好么惠州网站优化推广网站适不适合做优化怎么判断中英文的网站好优化排名郑州百度seo网站优化哪家好网站速度慢怎么优化封丘网站优化价格分析网站运营优化有什么好处梁子湖网站做优化怎么样永康关键词优化企业网站建设如何通过网站优化排名网站关键词优化论文对网站打开速度进行优化固原企业网站优化谢岗网站优化费用网站优化是什么职位seo优化网站突然降权

合作伙伴

天下标王

龙岗网络公司
深圳网站优化
龙岗网站建设
坪山网站建设
百度标王推广
天下网标王
SEO优化按天计费
SEO按天计费系统