Symbian CleanupStack工作机制解析

news/2024/7/4 0:51:23
 

对于 Symbian OS 中使用的 CleanupStack 机制,在这里不作好坏的评价,既然选择了在 Symbian 平台上开发,那最重要的就是了解它的机制,掌握并高效的利用好它。

       对于在 Symbian 平台上开发 GUI 或者 Server 程序, CleanupStack 已由框架创建,用户可直接使用 CleanupStack::PushL() CleanupStack::Pop() 等方法来控制可能的异常。在这样的框架下,用户无法了解 CleanupStack 是如何被创建,是如何工作的。

       当在 Symbian 平台上开发 Console 程序或者使用多线程时,异常清理栈 CleanupStack 就必须由用户自己创建和维护。 Symbian 封装了其中的核心机制,使得用户可以非常方便的创建 CleanupStack 清理栈并使用它。典型的代码如下:

 

TInt ThreadEntry(TAny *arg)     // 用户线程的入口函数

{

    TInt retCode = 0;                        // 函数异常退出的错误代码

    CTrapCleanup* cleanupstack = CTrapCleanup::New();  // 创建 CleanupStack 清理栈

    if(cleanupstack == NULL)    

           return -1;

       TRAP(retCode,Fun_EntryL());   // 捕获 Fun_EntryL() 异常退出

       If(retCode != KerrNone)

       {

              //Handle_Error();

       }

delete cleanupstack;

    return retCode;

}

 

Void Fun_EntryL()

{

    CTestObj *obj = CTestObj::NewL();  // 创建 CTestObj 时可能 Leave

    CleanupStack::PushL(obj);

    Obj->FuncMayLeaveL();              // FuncMayLeaveL() 方法调用可能 Leave

    CleanupStack::PopAndDestroy();

}

 

       上述主要的方法已做大致的说明,接下去具体分析 CleanupStack 清理栈创建和工作过程。 CleanupStack 类只是 Symbian OS 提供的针对清理栈的静态类,也就是工具类, Symbian OS 中真正的清理栈功能是由 CCleanup 实现的。但如上述代码,我们在创建清理栈时并没有直接创建 CCleanup 对象,而使用 CTrapCleanup::New() 方法创建了一个 CTrapCleanup 对象,这其中就是核心所在。

       当调用 CTrapCleanup::New() 方法时,真正做了什么?首先,要使用清理栈,则必须创建 CCleanup 对象;其次在 CTrapCleanup 中创建了一个 TCleanupTrapHandler 对象。在创建了这些对象后,调用 User::SetTrapHandler() 将生成的 TCleanupTrapHandler 安装到当前线程中以备后用。

       在用户线程中,当调用可能 Leave 的方法时,必须用 TRAP/TRAPD 宏加以捕获。 TRAP/TRAPD 宏调用 TCleanupTrapHandler::Trap() 以标志开始异常捕获,当被 TRAP 宏监视的函数 Leave 时,调用 TCleanupTrapHandler::Leave() 方法控制其 CCleanup 对象完成之前已压入清理栈的对象;当被 TRAP 监视的函数正常时,调用 TCleanupTrapHandler::UnTrap() 方法取消异常捕获。

       同样,在可能 Leave 的方法中,如上述的 Fun_EntryL() ,当调用 CleanupStack::PushL(obj) 方法时,其内部是通过 User::TrapHandler() 获得当前线程中已安装的 TCleanupTrapHandler 对象,然后通过 TCleanupTrapHandler::Cleanup() 获得清理栈类,最后由清理栈类真正完成压栈、出栈和异常时栈内对象的内存释放。

       总结,清理栈的工作是以一个 TRAP/TRAPD 为单位的,在被某个 TRAP 宏监视的代码段内压入清理栈的对象,当出现异常 Leave 时,这些对象都能通过清理栈完成内存释放,不会导致内存泄露。但在不同 TRAP 宏压入的对象,在上述情况下是无法释放的,这点需要注意。

前面一节主要描述了 Symbian OS 中清理栈 CleanupStack 的核心基础结构及工作线路,以在用户线程中创建一个 CleanupStack 对象为例,详细分析了 CleanupStack 创建、调用的内部工作机制。本节将说明 CleanupStack 类针对不同对象,提供的不同方法,在发生 Leave 时的不同动作。

Symbian OS 提供用户操作清理栈的接口通过 CleanupStack 类展示,全部为静态方法。将对象压入清理栈的方法有 CleanupStack::PushL(CBase*) CleanupStack::PushL(TAny*) CleanupStack::PushL(TCleanupItem &) 三种。从方法的不同传入参数可基本看出,针对不同的对象类型,压栈方法将调用不同的 PushL 重载方法来实现不同对象的入栈,当然其目的不在于如何进栈,而在于当发生 Leave 时,之前被压入栈的对象将做不同的处理,接下去就将详细说明不同类对象 Leave 时的不同处理。

当对象继承自 Cbase 类时,将该对象压入清理栈时会调用 CleanupStack::PushL(CBase*) 重载方法。

class CHeapClass : public CBase

{

public :

    ~CHeapClass ();

    static CHeapClass* NewL ();

    static CHeapClass* NewLC ();

    void FuncL();

private :

    CHeapClass ();

    void ConstructL ();

private:

    TUint8* iBuf;

};

 

void CheapClass:: ConstructL()

{

    ……

iBuf = new TUint8[100];

……

}

 

CheapClass:: ~CHeapClass ()

{

    if(iBuf != NULL)

       delete[] iBuf;

}

       通常,当程序中需用到指向堆对象的局部变量时,为防止内存泄露,需在调用可能发生 Leave 的方法前,将该对象压入当前线程的清理栈中,如下:

 

void LocalFunc()

{

       CheapClass *obj = CheapClass::NewL();

    CleanupStack::PushL(obj);

    Obj-> FuncL();

    CleanupStack::PopAndDestroy();

}

       当调用代码 FuncL 出现 Leave 或者调用 CleanupStack::PopAndDestroy() 时,根据清理栈机制,此时就会释放相应对象。由于之前压入的对象 obj CBase 的派生类,该类的特点就是具有需析构函数。所以,当发生 Leave 时,清理栈类调用 delete 方法来删除该对象, delete 方法相应地能正确地调用到该派生类的析构函数,这样就能完成释放该对象及该对象所占有的资源。

    对于非 CBase 派生类,当压栈时调用 CleanupStack::PushL(TAny*) 方法。此时,当发生 Leave 或者调用 CleanupStack::PopAndDestroy() 时,清理栈内部所做的工作不同于上述情况。清理栈在清理对象时,只是简单的调用 User::Free() 来释放该对象。该重载方法适合没有析构函数的类对象 ( 该对象没有自己的独占资源需要释放 ) ,因为调用 User::Free() 方法不会导致类析构函数被调用。

    对于特殊情况,当调用出现 Leave 时,代码不仅仅要做简单的类对象释放,很明显上述方法都无法满足。 Symbian OS 中提供如 CleanupClosePushL CleanupDeletePushL CleanupReleasePushL 等方法,来补充适合非类对象内存释放的情况。对于这些方法的调用,其核心就是清理栈的第三种接口 CleanupStack::PushL(TCleanupItem &) 的应用。

       TCleanupItem(TCleanupOperation anOperation)

    当将一个TcleanupItem 对象压入清理栈后,程序调用出现Leave 或者调用 CleanupStack::PopAndDestroy() 时,在退出 TRAP 前,代码有机会在 TcleanupItem 对象中定义的TcleanupOperation 方法中先得到异常清理,TcleanupOperation 方法定义如下:

    typedef void(* TCleanupOperation)(TAny*)

在自定义的TcleanupOperation 方法中,用户有机会对程序异常做更多复杂和自定义的异常处理,而不是简单地只调用delete 方法或者User::Free() 来完成内存释放功能,在该方法,用户可以同时释放内存,释放该对象所占有的Symbian 资源等。

Symbian OS 提供的 CleanupReleasePushL() 等方法,封装了其中内部工作机制,使得用户可以方便的完成相应自定义清理方法。

class RTest ;

{

public :

void Release();

}

 

RTest testObj;

CleanupReleasePushL (testObj);

……   //Some Leave Func

CleanupStack::PopAndDestroy();

当调用 CleanupReleasePushL (testObj) 时,内部调用了工具类 CleanupRelease:: PushL() 方法,创建了一个 TCleanupItem 对象,并用对象 testObj void Release() 方法初始化 TCleanupItem 对象的 TcleanupOperation 方法,同时将该 TCleanupItem 压入清理栈。当程序 Leave 或者调用 CleanupStack::PopAndDestroy() 时,对象 testObj void Release() 方法将被调用,用户可在该方法中做相应的异常处理。

总结,当通过 CleanupStack::PushL(CBase*) CBase 派生类压入清理栈后,程序 Leave 时,该类的析构函数能被及时调用,能有机会释放该对象占有的内存资源;当通过 CleanupStack::PushL(TAny*) 方法将非 CBase 类对象压入清理栈后, 程序 Leave 时,清理栈仅简单的调用 User::Free() 方法释放该对象,而不会导致析构函数被调用;当通过 CleanupStack::PushL(TCleanupItem &) 方法将 TCleanupItem 对象压入清理栈后,程序 Leave 时, TCleanupItem 对象中定义的清理函数将被调用,可完成一些复杂情况下的异常清理。

 

开发提示:

       如上节所描述, TRAP 宏有较大的内存调用开销。所以,在代码中尽量控制频繁使用 TRAP 宏。在一些逻辑上不可分割的操作上,可利用 CleanupStack::PushL(TCleanupItem &) 重载方法,在程序发生 Leave 时,在自定义的异常处理方法中控制程序逻辑,而不采用 TRAP 宏判断。


http://www.niftyadmin.cn/n/2308453.html

相关文章

go zero 报错进阶指南中

在同一返回格式中出现错误 怎么修改也没用 httpx.SetErrorHandler(func(err error) (int, interface{}) {switch e : err.(type) {case *errorx.CodeError:return http.StatusOK, e.Data()default:return http.StatusInternalServerError, nil} }) 加上这个之后还得在返回格式…

symbian 模拟器 相关

(1)模拟器 里面测试的程序如何删除? for s60 2nd平台: 删除/epoc32/release/wins/udeb/z/system/apps/myapp的目录即可 for s60 3rd平台: a、删除/epoc32/release/winscw/udeb/myapp.exe b、删除/epoc32/release/winscw/udeb/z/private/1000…

S60 Qt 开发环境配置指南(Carbide gcce)

S60 Qt 开发环境配置指南 安装之前需要下载以下内容:ActivePerl 5.10.1 这是目前最新版本,S60 SDK需要perl 5.6.1以上版本http://www.activestate.com/activeperl/ JRE Java runtime, S60 SDK 需要1.5以上的版本,我一向觉得Java版本管理混乱…

GPL和LGPL的区别!

什么是 GPL、LGPL 和 GFDL?它们和源代码以及商业销售之间的关系是什么? GPL 是 GNU General Public License (GNU 通用公共许可证)的缩写形式;LGPL 是 GNU Lesser General Public License (GNU 宽通用公共许可证)的缩写形式,…

使用QtCreator 1.3开发Symbian程序

QtCreator 1.3的发布里增加了开发Symbian程序的支持。文档上说这是一个实验性的功能,我当了一把小白鼠试了一下,能正常工作。 以下是我的几个操作步骤。1. 兵马未动,粮草先行。该安装的东西都得先装上,基本上和利用Carbide做开发的…

Nokia 论坛Qt开发者培训资料

qt_for_mobile_slides_day_1 (Qt 偏底层知识,for windows/S60) qt_for_mobile_slides_day_2 (Qt 偏上层知识,for windows/S60 qt_for_mobile_slides_day_3 (Maemo 开发) exercise_day_1 demos_day_2

Symbian开发总结

83. 生成Dll,App时不能使用静态可写变量: static const char * KStrX "x"; 使用 OPTION GCC -save-temps 可以生成汇编代码,查找Bss和Text段就可以看到静态可写变量。 改为: static const char * const KStrX &q…

QT symbian 开发框架调研

Qt是一个跨平台的C图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所用功能。Qt是完全面向对象的,很容易扩展,并且允许真正地组件编程。 授权模式: Qt开放源代码,并且提供自由软件的用户协议。使得它…