`
liu86th
  • 浏览: 113609 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

[转]内存管理 --- 内存使用不当小结

 
阅读更多

 

 

因为我们的应用程序能够使用的内存有限,所以在编写代码的时候需要特别注意内存

使用问题。如下是一些常见的内存使用不当的情况。 


 ⑴查询数据库没有关闭游标 

描述: 

    程序中经常会进行查询数据库的操作,但是经常会有使用完毕 Cursor后没有关闭的情

况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操

作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。 

  

示例代码: 

 

 

 

Cursor cursor = getContentResolver().query(uri ...); 
if (cursor.moveToNext()) { 
    ... ...  
} 

 

 

修正示例代码: 

 

 

Cursor cursor = null; 
try { 
    cursor = getContentResolver().query(uri ...); 
    if (cursor != null && cursor.moveToNext()) { 
        ... ...  
   } 
} finally { 
    if (cursor != null) { 
        try {  
            cursor.close(); 
        } catch (Exception e) { 
            //ignore this 
        } 
    } 
}  

 

 

⑵ 构造 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) 方法。 

 

示例代码:

 

 

 

public View getView(int position, View convertView, ViewGroup parent) { 
    View view = new Xxx(...); 
    ... ... 
    return view; 
} 

 

 

修正示例代码: 

 

 

public View getView(int position, View convertView, ViewGroup parent) { 
    View view = null; 
    if (convertView != null) { 
        view = convertView; 
        populate(view, getItem(position)); 
        ... 
    } else { 
        view = new Xxx(...); 
        ... 
    } 
    return view; 
}
 

 

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

 

描述:

 

 

 有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被

使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是

必须的,视情况而定。可以看一下代码中的注释: 

    /** 

     * Free up the memory associated with this bitmap's pixels, and mark the 

     * bitmap as "dead", meaning it will throw an exception if getPixels() or 

     * setPixels() is called, and will draw nothing. This operation cannot be 

     * reversed, so it should only be called if you are sure there are no 

     * further uses for the bitmap. This is an advanced call, and normally need 

     * not be called, since the normal GC process will free up this memory when 

     * there are no more references to this bitmap. 

     */ 

 

  private void releaseBitmap(){ 
       
         //在这,我们分别预存储了第一个和最后一个可见位置之外的3个
位置的bitmap 
       
         //即dataCache中始终只缓存了(M=6+Gallery当前可见view的个
数)M个bitmap 
       
                     int start = mGallery.getFirstVisiblePosition()-3; 
       
                     int end = mGallery.getLastVisiblePosition()+3; 
       
                     Log.v(TAG, "start:"+ start); 
       
                     Log.v(TAG, "end:"+ end); 
       
                     //释放position<start之外的bitmap资源 
       
                     Bitmap delBitmap; 
       
                     for(int del=0;del<start;del++){ 
       
                             delBitmap = dateCache.get(del); 
       
                             if(delBitmap != null){ 
       
                                      //如果非空则表示有缓存的
bitmap,需要清理 
       
                                     Log.v(TAG, "release position:"+ 
del); 
       
                                     //从缓存中移除该del->bitmap的
映射 
       
                                     dateCache.remove(del); 
       
                                      delBitmap.recycle(); 
       
                             }
 

 

⑷ 释放对象的引用 

 

 

描述: 

    这种情况描述起来比较麻烦,举两个例子进行说明。 

示例A: 

假设有如下操作

 

 

public class DemoActivity extends Activity { 
    ... ... 
    private Handler mHandler = ... 
    private Object obj; 
    public void operation() { 
    obj = initObj(); 
    ... 
    [Mark] 
    mHandler.post(new Runnable() { 
           public void run() { 
            useObj(obj); 
           } 
    }); 
    } 
}

 

 

我们有一个成员变量 obj,在operation()中我们希望能够将处理obj实例的操作post

到某个线程的MessageQueue 中。在以上的代码中,即便是 mHandler 所在的线程使用

完了obj所引用的对象,但这个对象仍然不会被垃圾回收掉,因为 DemoActivity.obj还保

有这个对象的引用。所以如果在DemoActivity中不再使用这个对象了,可以在[Mark]的

位置释放对象的引用,而代码可以修改为:

 

 

... ... 
public void operation() { 
    obj = initObj(); 
    ... 
    final Object o = obj; 
    obj = null; 
    mHandler.post(new Runnable() { 
        public void run() { 
            useObj(o); 
        } 
    } 
} 
... ... 

 示例B: 

    假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如

信号强度等),则可以在LockScreen 中定义一个PhoneStateListener 的对象,同时将它

注册到TelephonyManager 服务中。对于LockScreen 对象,当需要显示锁屏界面的时候

就会创建一个LockScreen 对象,而当锁屏界面消失的时候LockScreen 对象就会被释放

掉。 

    但是如果在释放LockScreen 对象的时候忘记取消我们之前注册的

PhoneStateListener 对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界

面显示和消失,则最终会由于大量的LockScreen 对象没有办法被回收而引起

OutOfMemory,使得system_process进程挂掉。 

    总之当一个生命周期较短的对象A,被一个生命周期较长的对象B保有其引用的情况

下,在A的生命周期结束时,要在 B中清除掉对A的引用。

 

⑸其他 

 

 

Android 应用程序中最典型的需要注意释放资源的情况是在Activity的生命周期中,在

nPause()、onStop()、onDestroy()方法中需要适当的释放资源的情况。由于此情况很基

础,在此不详细说明,具体可以查看官方文档对Activity生命周期的介绍,以明确何时应

该释放哪些资源。 

分享到:
评论

相关推荐

    什么是虚拟内存

    它的作用与物理内存基本相似,但它是作为物理内存的“后备力量”而存在的,但是,它并不是在只有物理内存不够用时才发挥作用的,也就是说在物理内存够用时也有可能使用虚拟内存,如果你虚拟内存设置过小则会提示...

    AWorks编程:嵌入式C语言的内存管理

    很多工程师都知道,C/C++语言与其他语言不同,它需要开发者自己...作为嵌入式C的开发人员,了解其内存管理的原理能使其更加正确地使用内存资源以及定位程序的bug。本文将以C语言为例介绍动态内存管理的原理。  动

    iOS内存监测工具FBMemoryProfiler.zip

    应用程序可能会不当的耗尽内存、崩溃,或者遭遇大幅度的性能降低。当分配了一块内存,并设置了对象之后,如果在使用完了之后忘记释放,这就会发生内存泄露。这意味着系统是无法回收内存并交予他人使用,这也最终意味...

    C++出错提示英汉对照表

    Incorrect use of default --------------------- Default使用不当 Invalid indirection ---------------------无效的间接运算 Invalid pointer addition ------------------指针相加无效 Irreducible expression...

    VC使用CRT调试功能来检测内存泄漏.rar_VC 内存_VC 调试_Vc_内存泄漏

    VC使用CRT调试功能来检测内存泄漏 C/C++ 编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么 C/C++ 应用程序正好印证了这句话。在 C/C++ 应用程序...

    一文秒懂C语言/C++内存管理(推荐)

    在内存管理中,由于是操作系统内存,使用不当会造成毕竟麻烦的结果。本文将从系统内存的分配、创建出发,并且使用例子来举例说明内存管理不当会出现的情况及解决办法。 一、内存 在计算机中,每个应用程序之间的内存...

    unix-privesc-check - unix配置不当检查工具.mht

    unix-privesc-check - unix配置不当检查工具.mht

    编程经验谈:如何正确使用内存

    对于初学者来说,内存是个神秘的...程序的绝大部分错误,也是在于内存的使用不当造成的,而且这些错误有些都是隐藏很深的。所以,如何掌握内存的使用,通晓系统对内存的管理手段,将是软件成功的一个非常关键的因素。

    iOS/OSX内存管理(一):基本概念与原理

    内存管理是在程序需要时程序员分配一段内存空间,而当使用完之后将它释放。如果程序员对内存资源使用不当,有时不仅会造成内存资源浪费,甚至会导致程序crach。本文作者从基本概念开始,剖析内存管理的方法与问题。...

    如何解决torch.tensor中的copy-方法造成的内存泄漏?

    python虽然不用主动管理内存,然而如果处理不当,会造成严重的内存泄露。比如在进行机器学习训练的过程中就会发生这种情况,导致程序难以长时间连续运行。本文给大家带来处理这类问题的一种处理思路。

    不当得利制度初探-论文.zip

    不当得利制度初探-论文.zip

    网络游戏-对计算机网络中行为不当节点的管理.zip

    网络游戏-对计算机网络中行为不当节点的管理.zip

    误区7.2 线面位置关系定理使用不当失误-2019届高三数学提分精品讲义.doc

    误区7.2 线面位置关系定理使用不当失误-2019届高三数学提分精品讲义.doc

    冲转参数不当导致转子弯曲.pdf

    冲转参数不当导致转子弯曲.pdf

    vc内存泄露检测

    在 C/C++ 应用程序开发过程中,动态分配的内存处理不当是最常见的问题。其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不会引起我们的注意,但...

    工程招投标与合同管理--复习资料(1).doc

    5.施工企业的项目经理由于管理不当,具体施工人员在施工中产生了一些问题,导致本应顺利完成的施工任务延误,监理单位履行了合同规定的职责,建设单位应当向[ B ]提出赔偿要求。 A.监理单位 B.施工单位 C.项目...

    06-信息泄露之配置不当.pdf

    信息泄露之配置不当

    jodconverter-2.2.2.jar jodconverter-core-3.0-beta-3.jar aspose-pojie.zip

    openoffice需要用的jar, office转pdf jodconverter-2.2.2.jar网上很少 ,亲测可用,jodconverter-core-3.0-beta-3.jar 亲测可用 项目要实现在线预览,将office转pdf 流形式输出到前端openoffice需要用的jar, ...

    信息系统管理制度-定稿.docx

    (二)系统开发不符合内部控制要求,授权管理不当,可能导致无法利用信息技术实施有效控制。 (三)系统运行维护和安全措施不到位,可能导致信息泄漏或毁损,系统无法正常运行。 第四条 职责: (一)信息统计中心...

Global site tag (gtag.js) - Google Analytics