hanming
2004-03-02, 06:05
小弟边看SDK,边穇的东西,有些地方不是很准确,还请高手指点一下,小弟会立即修改。谢谢先。
四.内存管理
1. 内存管理总览
(1) 目的
讨论程序运行时分配的内存与程序运行所要的内存。内存,做为EPOC程序的基石,做为一块有限的资源,必须被小心使用,尤其是在出现异常的情况下,因此,在CleanUp Support API中,异常处理与内存管理紧密的连系在一起。
(2) 体系结构
UiKon Core framework用这些API为每个GUI程序提供良好的内存管理的基本体系结构。每个GUI程序都在异常出现的时候都支持Clean up Memory,且在调试时能够检测内存泄漏。
2. Cleanup 支持概述
(1) 目的
提供处理程序异常和当异常发生时清除内存的方法
(3) 体系结构
EPOC的Cleanup策略与普通类(尤其是CBase的派生类)紧密联系在一起,
(4) Description
这些API分为三个重点部分:异常处理(Exception handling),清除栈(cleanup satck)和(general cleanup item)
l 异常处理(Exception Handling)
a. EPOC并不使用标准C++的异常处理,(try, catch, throw),而是使用自己惯用的方法,一个异常被称为Leave
b. 捕获器(trap harness)在程序中定义了一个当异常发生时会立即跳转去的点。程序员可以用TRAP 或TRAPD这两个宏来设置捕获器。
c. 通过调用系统静态功能API的User类的函数(User::Leave())时会触发Leave.许多系统函数与用户代码都有可能触发Leave.
l 清除栈(Cleanup Stack)
a. 异常发生时,任何在堆上分配的内存,如通过New()创建的对象,其指针就会被遗弃在内存中,造成内存泄漏。要防止这种内存泄漏,就需要程序能记录这些对象,一旦发生泄漏,系统就能自动找到这些对象并清除它们。即所谓的清除栈。
b. GUI程序的Application Frameword提供了清除栈,而其它的应用程序就要显示的用CTrapCleanup去显示的建立清除栈。
l General Cleanup Item
a. 通常Cleanup Stack 只处理CBase的派生类和无类型的对象(TANY*) ,General Cleanup Item允许将其它类对象压入Cleanup Stack,然后让调用者调用指定的函数去完成清除工作。其接口定义在TCleanupItme;
3. 内存分配总览
其分为两个重要的部分:Chunk,Heap
Chunk:
(1) Chunk是被映射到线性连续地址上的RAM区域,当一个进程运行时,地址空间被分成1至3个Chunk.
(2) Stack/Heap Chunk:被进程的主线程使用的堆和栈。其綺常存在
(3) Code Chunk:只有进程被装入到RAM中,才存在。
(4) Data Chunk: 只有里程拥有静态数据时才存在。
(5) 程序允许附加其它的Chunk,Global Chunk能被其它的进程访问,所以允许大量的内存共享。 其接口定义在RChunk
(6) TFindChunk 用于查找其它进程建立的Chunk.
Heap:
(1) 堆用于显示的动态分配内存,EPOC定义C++的new操作符在当前的线程堆栈中创建对象。
(2) 堆可以监控内存泄漏,在一个进程中的各个线程之间共享,在CELL LEVEL下存取与操作。
五.使用Cleanup
1.异常处理
a) 错误类型与恢复
错误条件可以分为以下三类
(1) 程序错误,如数组访问超界,可以用_ASSERT_DEBUG宏来检查,一般解决的方法是重写代码。
(2) 环境错误,如内存不足,磁盘空间不足,检查方法有两种,一是如错误出现在一个操作之后,就可以检查返回码是不是KErrNone,另外一种是使用异常处理和清除技术。
(3) 用户错误,如源代码中的语法错误,在对话框中输入错误的数据。
b) C++异常处理
EPOC有其自己的异常处理机制,注意在使用C++异常处理的同时,Cleanup与两段构造同样需要。
c) 基本异常处理支持
操作系统支持如下基本的异常处理
TRAP宏与其变量,允许代码运行在捕获器下的TRAPD宏。
User::Leave()调用,其将会终止当前的函数,并指定一个错误码,返回到捕获器中。
d) User::Leave()的使用
User::Leave()用以在发生异常的时候立即中止功能模块的处理。
void doExampleL()
{
CExample* myExample = new CExample;
if (!myExample) User::Leave(KErrNoMemory);
// leave used in place of return to indicate an error
// do something
myExample->iInt = 5;
testConsole.Printf(_LIT("Value of iInt is %d.\n"),myExample->iInt);
// delete
delete myExample;
}
如果NEW失败的话便会调用User::Leave();
e) TRAP使用
在捕获器下执行将要发生异常的程序
可能发生异常的函数或是调用其它可能发生异常函数的函数都必须在捕获器下执行。如果在一个函数调用了User::Leave(),那么控制权将立即返回到最近的TRAP中去。通常会定义一个变量用以了取得错误码。当没有异常发生时,函数调用完后执行TRAP,但其错误码不会改变。
TInt E32Main()
{
testConsole.Title(); // write out title
testConsole.Start(_LIT("Example")); // start a new "test"
// The leave variable
TInt r=0;
// Perform example function. If it leaves,
// the leave code is put in r
TRAP(r,doExampleL());
// Test the leave variable
if (r)
testConsole.Printf(_LIT("Failed: leave code=%d"), r);
testConsole.End(); // finish
testConsole.Close(); // close it
return KErrNone; // and return
}
TRAPD的使用
用法与TRAP相同,只是不用定义变量。
TRAPD(leaveCode,SomeFunctionL()); // call a function
if (leaveCode!=KErrNone) // check for error leave code
{
// some cleanup
}
TRAPD(leaveCode,value=GetSomethingL()); // get a value
if (leaveCode!=KErrNone) // check for error leave code
{
// some cleanup
}
else { // didn’t leave: value valid
}
f) new with automatic leave on failure的使用
如果NEW失败的话,则意味着必须离开这段程式,也就没有检查NEW返回的结果的必要了。
void doExampleL()
{
// attempt to allocate, leave if could not
CExample* myExample = new (ELeave) CExample;
// new (ELeave) replaces new followed by check
// do something
myExample->iInt = 5;
testConsole.Printf(_LIT("Value of iInt is %d.\n"),myExample->iInt);
// delete
delete myExample;
}
g) 捕获器(trap harness)放在哪里最好???
捕获器可以嵌套使用,如果一个程序引起异常,控制权将返回到最近的捕获器去,这就让嵌套子程序有其自己的捕获器。良好的捕获器必须能够准确的知道错误类型并能做出恢复。
所有的GUI程序都提供了一个顶级(嵌套级别)的捕获器,如果异常发生,而用户没有去处理他,那么GUI程序所提供的捕获器就会响应这个错误,并做出相应的处理。
大多数的程序的捕获器都会处理用户的命令,但对于一些特别的情况,捕获器还会处理一些特殊命令,a much finer_grain approach.
对于大型的应用程序,最好有一个单一的恢复单元,最好在一些特殊地方放置捕获器。
四.内存管理
1. 内存管理总览
(1) 目的
讨论程序运行时分配的内存与程序运行所要的内存。内存,做为EPOC程序的基石,做为一块有限的资源,必须被小心使用,尤其是在出现异常的情况下,因此,在CleanUp Support API中,异常处理与内存管理紧密的连系在一起。
(2) 体系结构
UiKon Core framework用这些API为每个GUI程序提供良好的内存管理的基本体系结构。每个GUI程序都在异常出现的时候都支持Clean up Memory,且在调试时能够检测内存泄漏。
2. Cleanup 支持概述
(1) 目的
提供处理程序异常和当异常发生时清除内存的方法
(3) 体系结构
EPOC的Cleanup策略与普通类(尤其是CBase的派生类)紧密联系在一起,
(4) Description
这些API分为三个重点部分:异常处理(Exception handling),清除栈(cleanup satck)和(general cleanup item)
l 异常处理(Exception Handling)
a. EPOC并不使用标准C++的异常处理,(try, catch, throw),而是使用自己惯用的方法,一个异常被称为Leave
b. 捕获器(trap harness)在程序中定义了一个当异常发生时会立即跳转去的点。程序员可以用TRAP 或TRAPD这两个宏来设置捕获器。
c. 通过调用系统静态功能API的User类的函数(User::Leave())时会触发Leave.许多系统函数与用户代码都有可能触发Leave.
l 清除栈(Cleanup Stack)
a. 异常发生时,任何在堆上分配的内存,如通过New()创建的对象,其指针就会被遗弃在内存中,造成内存泄漏。要防止这种内存泄漏,就需要程序能记录这些对象,一旦发生泄漏,系统就能自动找到这些对象并清除它们。即所谓的清除栈。
b. GUI程序的Application Frameword提供了清除栈,而其它的应用程序就要显示的用CTrapCleanup去显示的建立清除栈。
l General Cleanup Item
a. 通常Cleanup Stack 只处理CBase的派生类和无类型的对象(TANY*) ,General Cleanup Item允许将其它类对象压入Cleanup Stack,然后让调用者调用指定的函数去完成清除工作。其接口定义在TCleanupItme;
3. 内存分配总览
其分为两个重要的部分:Chunk,Heap
Chunk:
(1) Chunk是被映射到线性连续地址上的RAM区域,当一个进程运行时,地址空间被分成1至3个Chunk.
(2) Stack/Heap Chunk:被进程的主线程使用的堆和栈。其綺常存在
(3) Code Chunk:只有进程被装入到RAM中,才存在。
(4) Data Chunk: 只有里程拥有静态数据时才存在。
(5) 程序允许附加其它的Chunk,Global Chunk能被其它的进程访问,所以允许大量的内存共享。 其接口定义在RChunk
(6) TFindChunk 用于查找其它进程建立的Chunk.
Heap:
(1) 堆用于显示的动态分配内存,EPOC定义C++的new操作符在当前的线程堆栈中创建对象。
(2) 堆可以监控内存泄漏,在一个进程中的各个线程之间共享,在CELL LEVEL下存取与操作。
五.使用Cleanup
1.异常处理
a) 错误类型与恢复
错误条件可以分为以下三类
(1) 程序错误,如数组访问超界,可以用_ASSERT_DEBUG宏来检查,一般解决的方法是重写代码。
(2) 环境错误,如内存不足,磁盘空间不足,检查方法有两种,一是如错误出现在一个操作之后,就可以检查返回码是不是KErrNone,另外一种是使用异常处理和清除技术。
(3) 用户错误,如源代码中的语法错误,在对话框中输入错误的数据。
b) C++异常处理
EPOC有其自己的异常处理机制,注意在使用C++异常处理的同时,Cleanup与两段构造同样需要。
c) 基本异常处理支持
操作系统支持如下基本的异常处理
TRAP宏与其变量,允许代码运行在捕获器下的TRAPD宏。
User::Leave()调用,其将会终止当前的函数,并指定一个错误码,返回到捕获器中。
d) User::Leave()的使用
User::Leave()用以在发生异常的时候立即中止功能模块的处理。
void doExampleL()
{
CExample* myExample = new CExample;
if (!myExample) User::Leave(KErrNoMemory);
// leave used in place of return to indicate an error
// do something
myExample->iInt = 5;
testConsole.Printf(_LIT("Value of iInt is %d.\n"),myExample->iInt);
// delete
delete myExample;
}
如果NEW失败的话便会调用User::Leave();
e) TRAP使用
在捕获器下执行将要发生异常的程序
可能发生异常的函数或是调用其它可能发生异常函数的函数都必须在捕获器下执行。如果在一个函数调用了User::Leave(),那么控制权将立即返回到最近的TRAP中去。通常会定义一个变量用以了取得错误码。当没有异常发生时,函数调用完后执行TRAP,但其错误码不会改变。
TInt E32Main()
{
testConsole.Title(); // write out title
testConsole.Start(_LIT("Example")); // start a new "test"
// The leave variable
TInt r=0;
// Perform example function. If it leaves,
// the leave code is put in r
TRAP(r,doExampleL());
// Test the leave variable
if (r)
testConsole.Printf(_LIT("Failed: leave code=%d"), r);
testConsole.End(); // finish
testConsole.Close(); // close it
return KErrNone; // and return
}
TRAPD的使用
用法与TRAP相同,只是不用定义变量。
TRAPD(leaveCode,SomeFunctionL()); // call a function
if (leaveCode!=KErrNone) // check for error leave code
{
// some cleanup
}
TRAPD(leaveCode,value=GetSomethingL()); // get a value
if (leaveCode!=KErrNone) // check for error leave code
{
// some cleanup
}
else { // didn’t leave: value valid
}
f) new with automatic leave on failure的使用
如果NEW失败的话,则意味着必须离开这段程式,也就没有检查NEW返回的结果的必要了。
void doExampleL()
{
// attempt to allocate, leave if could not
CExample* myExample = new (ELeave) CExample;
// new (ELeave) replaces new followed by check
// do something
myExample->iInt = 5;
testConsole.Printf(_LIT("Value of iInt is %d.\n"),myExample->iInt);
// delete
delete myExample;
}
g) 捕获器(trap harness)放在哪里最好???
捕获器可以嵌套使用,如果一个程序引起异常,控制权将返回到最近的捕获器去,这就让嵌套子程序有其自己的捕获器。良好的捕获器必须能够准确的知道错误类型并能做出恢复。
所有的GUI程序都提供了一个顶级(嵌套级别)的捕获器,如果异常发生,而用户没有去处理他,那么GUI程序所提供的捕获器就会响应这个错误,并做出相应的处理。
大多数的程序的捕获器都会处理用户的命令,但对于一些特别的情况,捕获器还会处理一些特殊命令,a much finer_grain approach.
对于大型的应用程序,最好有一个单一的恢复单元,最好在一些特殊地方放置捕获器。