Symbian的内存管理
对于手机来讲,内存资源是非常有限的,良好的内存分配管理机制是非常重要.如要内存没有很好的分配及捕获清理, 会导致内存溢出、数据丢失,系统崩溃,或者有一些意想不到的灾难性后果发生.
在讨论内存管理之前,要明白两个关于内存的二个很重要的概念:堆、栈,传统的数据类型变量及类成员变量的内存是分步在栈上的,堆内存是通过关键字new或(New(Eleave))来实例化的,在Symbian中,堆类是从CBase类继承的,是通过指针来引用的.
在处理一个函数状态时,只有二种状态,一是成功,二是失败;Symbian在成功时,返回KErrNone(KErrNone的值是0),失败返回一个错误码如(KErrNotFound,KErrNoMemory,)。良好的编程习惯是在调用后,无论是否有错,用if语句进行判断;
Symbian在内存管理机制上做得非常的好,采用了不同平台的独特机制:
1.陷井
Symbian提供了二个宏用来陷井捕获:
设置陷井:
TRAP宏 TRAP(error,function())
TRAPD宏 TRAPD(error,Function())
以上二个宏基本上相似,区别在于:TRAP宏在使用之前,要先定义里面的变量error,而TRAPD中的error变量无需定义,包含了TInt error该段代码.要注意的是error参数是TInt类型.
捕获陷井:
Symbian通过一个User静态类来进行返回错误码,例如:
User::Leave(code)
User::LeaveNoMemory()
User::LeaveIfError(error)
User::LeaveIfNull(TAny* ptr)
如果没有捕获到错误,error的值就是0.反之则是非0值;
例:
void Fun1()
{
TInt err = 0;
TRAP(err,Fun2L());
if(!(0==err))
{
错误处理
}
else
{
}
}
void Fun2L()--------------------------------------注意函数名:Fun2L()
{
TInt iValue = 0;
if (0==iValue)
User::Leave(1);
}
采取陷井捕获异常,程序的效率不高,关于陷井的运行效率,在这里就不多说明了。呵呵
2. 压栈清理
压栈清理是Symbian的独特机制,在对内存处理非常独特,指针变量可以压到清理栈,如果发生异常,由清理栈负责回收内存,如果没发生异常,应手动将其弹出栈,Symbian提供了一个静态类CleanupStack的API负责处理;
void FunL()
{
CPerson* person = new(ELeave)CPerson;
/*注意:Symbian重载了new操作符,new(ELeave)用于在分配内存时出现异常,清理栈会自动清除该块内存,避免野指针的情况发生.
*/
CleanupStack::PushL(person);//将person压入栈
....
CleanupStack::Pop(person);//从清理栈弹出压入的person;
//或者使用另:CleanupStack::PopDestory(1);或者CleanupStack::PopDestory(person);//
}
3.二重构造
Symbian提出的二重构造概念,同样在C++和java中可以使用.但JAVA是由虚拟机自动回收内存.二重构造是通过类的一个静态方法NewL/NewLC,进行构造对象,能过在NewL/NewLC构造的方法调用ConstructL()方法进行初始化成员函数.从而避免了分配内存成功但进行构造对象时出现错误的现象.在NewL/NewLC中进行压栈,如果分配内存失败,则由清理栈处理内存的回收.如果分配内存成功,便调用ConstrucL进行初始化成员变量.
注意:如果用户自定义的类是C类,是必须要继承CBase.
class CPerson : public CBase
{
private:
CPerson();
void ConstructL(TInt age,char* apname);
public:
static CPerson* NewL(TInt age,char* apname);
};
CPerson::Cperson* NewL(TInt age,char* apname)
{
char* ipName = new char[strlen(apname)+2];
strcpy(ipName,apname);
CPerson person = new(ELeave)CPerson;
CleanupStack::PushL(person);
person->ConstructL(age,apname);
CleanupStack::Pop(person);//或者CleanupStack::PopDestroy(1)或者CleanupStack::PopDestroy(person);
}
...
发生任何不可恢复的错误时,会出现严重的错误panic,具体panic下次在讨论.
二、Symbian命名约定
我老师经常对我讲过一句话“代码是写给人看的.”,这句话是很有道理的,也就是说遵守一定的命名约定,有助于同行交流。
关于类,Symbian大致分了四种类:T(数据类型类)、C(派生于CBase的堆分配类,)、R(资源类)、M(接口类).当然,定义不同的类时,应在类名前加类的前缀(T、C、R、M)。
1.类的成员变量应以i开头,函数参数应以"a"开头;
class TMyClass
{
TInt iMyValue;
void MyAddFunc(TInt aArg1,TInt aArg2);
void MyAddFuncL(TInt aArg1,TInt aArg2);-------->后缀L的约定是该函数可能产生异常退出;
void MyAddFuncLC(TInt aArg1,TInt aArg2); ---------->后缀LC的约定表示成功完成之后,返回值会被压入清理栈中;
};
2.常量应加前缀K. const CInt KMyconstant;
3.枚举应加T开头
enum TColors
{
ERed,
EGreen
}
4.宏全部为大写
#define MY_HARDCODED_VALUE (25)
5.