Symbian内存管理

来源:百度文库 编辑:神马文学网 时间:2024/04/29 03:12:06
在Symbain OS中内存管理的主要任务是:如何为程序分配内存以及如何在程序的内部分配内存。
Symbian OS 程序最根本和基础的东西就是内存,作为一个有限的资源,必须小心细致地处理,特别是当有错误或异常发生的时候。正是由于这样的原因,在支持清理机制的API中,异常处理和内存管理几乎是绑在一起的。
Uikon核心框架使用这些支持清理机制的API来管理内存,使GUI程序的基础架构具有良好的性能和表现。GUI程序还支持异常情况下内存清理,以及调试模式下的内存泄露检测。
一、Symbian OS的清理机制(cleanup)
清理机制是Symbain OS 程序对于程序异常处理的一种特有方式。当异常发生时,清理机制将清理错误的内存区域。Symbian OS的清理策略和它所有类的基类CBase类有着密切关系。要了解Symbian OS清理机制就必须清楚以下三个概念:异常处理(exception handling)、清理栈(cleanup stack)以及通用清理项(general cleanup item)。
1、异常处理 (Exception Handling)
Symbian OS没有使用C++的try…catch异常处理方式,而是使用了它自己所特有的方式:leave。在Symbian OS中,异常以 leave 的形式出现,trap harness可以在程序中设置一个点,使程序发生leave时回跳到这个点上,宏TRAP和TRAPD 可以在程序中设置这个点。调用系统API User 类的一些静态函数可以触发Leave ,例如 User::Leave()方法,这就相当于主动地抛出异常,当然某些系统函数或是用户代码,也有可能发生leave。
2、清理栈(Cleanup Stack)
当 leave 发生时,任何分配了资源的heap内存,例如通过new()方法创建的对象,他们将被孤立,因为leave一旦发生已指向他们的指针就不存在了,这样就导致了内存泄漏。为了防止内存泄漏发生,程序就有要记录那些已经被创建的对象,如果程序运行发生leave,那么系统可以自动找到并清理他们所占用的内存。这些工作可以通过清理栈来完成。CleanupStack类是支持清理栈的一个类。GUI应用程序拥有一个由应用程序框架所提供的清理栈,其他的应用程序必须用CTrapCleanup 类自己构建一个清理栈。
3、通用清理项(General Cleanup Item)
在默认情况下,清理栈只处理那些 CBase-based 类(也就是它所处理的类必须是由 CBase类继承下来的)和那些untyped 类型对象(用一个简单的内存释放语句就可以释放的对象)。通用清理项(General Cleanup Item)使其他类型的对象也可以放到清理栈中。TCleanupItem类是支持通用清理项的一个类。
二、Symbian OS的内存分配
内存分配管理的目的在于 能够使Symbian OS 进程通过底层函数访问和操纵内存区域。绝大多数的客户端程序不需要直接使用这些函数,那些在进程间共享内存区域以及在一个进程的线程间共享内存区域的程序会使用这些底层函数来管理内存。这里有两个概念需要了解 chunk(块) 和 heap(堆)。
1、Chunk(块)
chunk 是一组线性相邻的内存地址在RAM 中的映射。进程创建以后,它的地址空间包括1到3个chunk:
(1)stack/heap chunk:这里包括了进程的主线程所要使用的stack 和 heap。所以这个chunk 通常是进程所必须的。
(2)code chunk:这个chunk 只有当进程被加载到RAM时才出现。
(3)data chunk:只有当进程拥有静态数据的时候才会有这个chunk。
当然,程序可以还创建额外的chunk。 一个全局的chunk可以被其他进程访问,这样就实现了大量内存的共享。RChunk 类提供了对chunk的支持。TFindChunk 类可以用来查找其他进程创建的全局chunk。
2、Heap(堆)
heap 通常用于显式的动态内存分配 。Symbian OS定义了C++中new操作符创建对象到当前线程的heap中。Heap的功能可以是:
•监控内存泄漏:对于一个GUI程序来说,这个是经常发生的。
•在同一进程的线程间进行共享。
•在单元一级上进行访问和操作。
RHeap类提供了对heap的支持。如果heap 是当前线程的 heap,那么使用等价系统静态方法API 的User 类 将更加方便。这些系统静态方法API 同样也提供了宏来管理内存,以防止内存泄漏。
三、进程和地址空间
Symbian OS 的程序可以包含若干进程,每个进程包含若干在概念上并发执行的线程。每一个用户进程都有他自己私有的地址空间。一个用户进程不可以直接访问另外一个用户进程的地址空间。进程包括若干线程,他们运行在进程的特权级。
Kernel 进程是一个比较特殊的进程,它的线程运行在超级访问者级别,这个进程通常包括两个线程。
Kernel server 线程:是一个原始的进程,在系统启动时就已经存在。它可以在heap执行核心函数请求的内存分配或重新分配。
null 线程:当系统中没有其他可运行的线程时这个线程就开始运行,null 线程使处理器处于空闲状态,减少耗电
线程的地址空间包括若干chunk,在刚创建的时候,进程只有一个线程和1到3个chunk。如果进程创建了新的线程,那么一个新的chunk将被创建被分配给这个线程。每一个chunk都包括一个了stack,如果线程没有共享当前heap,那么在chunk中也将包括heap。
四、Chunks(块)
Chunk 把RAM映射到一个连续的虚拟地址。一个chunk中包括了一个保留区(reserved region)和和委托区(committed region)。保留区是一个连续的虚地址区域,它的大小可能是整个chunk的大小。在委托区中存放了真正映射到RAM的地址。chunk的大小是可以被动态修改的,允许委托区也可以修改大小,他的范围是从0一直到保留区大小,是处理器页面大小的整数倍。这样,就允许进程获得更多的内存空间。通常,委托区起始地址位于保留区底部。另外还可以创建 double-ended chunk ,那么委托区将是保留区的任意连续子集,他的大小也是处理器页面大小的整数倍,这种Chunk的委托区可以有两个顶端和底端,并且它们的大小也是可变的。
在chunk创建时可以指定chunk的最大空间,保留区大小应该小于这个最大值。.尽管这样,如果保留区请求比当前chunk更大的空间,那么chunk可以被重新分配空间,以允许保留区扩大。保留区可以扩大到撑满整个chunk.。
Local chunks(本地 chunk)
如果一个chunk对于创建它的进程是私有的,不允许被其他用户进程访问,那么那么这个chunk就是本地chunk,本地chunk是没有名字的。
Global chunks(全局chunk)
如果一个chunk可以被其他进程访问,那么这个chunk就是全局chunk。全局chunk是有名字的,这样,进程可以根据chunk的名字来访问他们。当进程打开一个全局chunk的时候,他把chunk映射到自己的地址空间,这样就可以对chunk进行直接访问和数据共享了。如果已经知道了 chunk的名称,那么使用 RChunk::OpenGlobal() 可以直接打开chunk.。如果只知道了chunk的部分名字,那么可以使用带 TFindChunk 型参数的 RChunk::Open()方法来打开chunk.。
五、Heaps(堆)
Each thread has a chunk which contains that thread’s program stack. For the main thread of a process, this chunk also contains the thread’s heap. A program’s request for memory is allocated from this heap. For example, a code fragment such as:
每一个线程都有一个包含了自身程序栈(program stack)的chunk。.对于进程的主线程来说,这个chunk中同样也包含了线程heap。程序对于内存的请求都是从这个heap的地址空间来分配的,例如有以下代码:
CArrayFixFlat<...>* fixflat;
...
fixflat = new (ELeave) CArrayFixFlat<...>(3);
程序请求了heap中部分的内存地址,并把地址返回给调用者。请求heap中的内存必须是显式的,同样,释放这些内存时也必须进行显式调用。
Structure of a heap(heap 结构)
heap包括两个单元列表。一个是已经分配的内存单元列表,一个是还未分配的内存单元列表。两个列表都在heap对象上。内存单元由单元头和单元体组成,单元体实际上就是一个内存区。单元头是在e32std.h 中定义的 RHeap::SCell 结构体,他是RHeap类的一部分。
如何共享heap
heap通常被同一个进程的线程所共享当一个线程创建时:
•它可以和父线程使用同一个heap。
•父线程同时为新线程创建一个新的heap。
•新线程使用系统为它创建的heap。
这里,只有第一和第二中情况可以认为是heap的共享。