内存管理模型

2024-08-20

内存管理模型(精选七篇)

内存管理模型 篇1

内存管理模块管理着系统的物理内存, 以及对应得一些硬件机制, 向操作系统其他部分提供服务。在嵌入式实时系统中, 内存管理机制是一个重点和难点的问题, 内存管理机制必须满足以下几个特性: (1) 实时性 (2) 可靠性 (3) 高效性。基于对VxWork系统内存管理进行详细研究, 提出了一种实时监控的内存管理方法, 并在实现过程中进一步完善。采取事先分配大块内存的方式, 以扇区管理表模型对内存进行分类管理。程序运行过程中, 根据不同的内存使用方式分配不同类型的内存块;不同类型的内存块定义不同的生命周期。由专一的任务 (task) 对内存所有扇区进行定时扫描, 发现超过生命周期的内存就强制释放;发现有越界使用的内存, 就采取地址回显的方式定位发生内存越界的函数、代码。以此对内存使用进行跟踪、调试, 达到避免内存泄漏、内存越界的目的。

基于VxWorks的内存管理, 一般说来, 如果只使用操作系统为我们提供的malloc () 和free () (C语言) 函数对内存进行操作, 而不进行额外的管理, 总是不可避免地甚至大量出现内存泄漏和内存越界的问题。而仅仅依靠操作系统对内存的管理远远不够让我们及时发现并解决问题。此外, 往往由于本身提供的内存较小, 软件要求的实时性较高, 这就要求必须对内存进行妥善的管理。

为此, 本文提出了一种基于生命周期的内存管理模型, 提高了内存使用的安全性和可靠性。

2、基于VxWorks的内存管理

2.1内存管理模块

基于生命周期的内存管理模型首先是在应用程序刚启动就得定制大块内存, 这块内存应该尽可能大, 它要满足的需求包括:程序运行过程中临时申请的内存;任务之间传递消息申请的内存;永久性申请用于存储初始化数据和运行数据的内存。总之, 程序运行过程中所使用的动态内存 (栈内存除外) 将不再使用系统提供的API函数申请。

这块内存可以定制的方式包括:

1. 如果操作系统运行区比较大, 可以使用API函数malloc () 进行申请;

2.如果用户预留空间足够大, 可以直接定义用户预留空间内存为程序运行过程中的动态内存。

定制完内存之后, 按照扇区管理表的模型把内存分成若干内存块 (举例按照每128 byte为一个内存块) 。定义基于生命周期的内存管理模型按照如下原则:

1.在定制的内存的初始地址开始定义内存管理表, 内存管理表记录每个内存块的空闲情况和每一个指针的地址。内存管理表要足够大。用来记录内存块空闲情况的字段中, 每一个bit表示一个内存块。当内存块被使用时, 该bit为1;内存块未被使用时, 该bit就为0。记录指针的字段用于记录程序当前运行过程中所有分配内存的指针的地址。

2. 每个指针指向的内存, 从初始地址开始, 记录这个指针的"内存块上下文"。"内存块上下文"中的信息包括:该指针指向的内存的类型, 指针指向的内存所占用的内存块的数目、序号, 该指针所属的函数的地址。

3.不同类型的内存 (指针) , 定义不同的生命周期。

4.程序运行过程中, 根据用户自定义的API进行内存操作。

5.内存管理模块作为一个独立的任务 (task) 运行, 不断地对内存管理表里的指针进行扫描, 监控。监控的内容包括:生命周期是否结束, 是否存在多个指针重复使用同一个内存块, 实时报告内存使用情况。

如果该指针的生命周期结束, 系统自动把指针指向的内存块释放, 同时把指针置为NULL;如果存在多个指针重复使用同一个内存块, 系统通过assert () 函数把每个指针的"内存上下文"输出到log文件, 以便及时调试。

5.用户自定义的申请内存的API函数会首先检查是否有可用的内存块;如果有, 会再继续检查是否有其它的指针在占用这个可用的内存块;如果有, 则通过assert () 函数把指针的"内存上下文"输出到log文件, 以便及时调试;如果没有, 则把这个内存块分配给当前指针, 同时更新内存管理表中表示该内存块的bi的信息。

7.用户自定义的释放内存的API函数会首先根据当前指针的"内存上下文", 更新相应内存块在内存管理表中的bit为0;然后把当前指针置为NULL。

这种内存管理模型的优点是:减少了频繁使用malloc () 和free () 对系统资源造成的浪费;用户使用内存更加灵活;基于生命周期的方案可以在一定程度上减少内存泄漏和内存越界的危险;可以避免野指针。

2.2 内存类型

根据程序实际需要, 内存类型会适时进行修改。

typedef enum{

MEM_SCRATCH//临时申请的内存, 并会很快释放, 生命周期很短

MEM_MSG//用于任务间传递消息申请的内存, 生命周期较长MEM_DATA//用于存储初始化数据和运行数据, 生命周期为无限。

}MEM_TYPE;

2.3 内存API

基于内存模型以及内存类型, 本文定义了若干操作内存的API以供在程序运行过程中使用。如下所示:

1.ALLOC_MEM (char*pointer, MEM_TYPE memType, insize) :申请一块内存给pointer, 类似于malloc () 函数;如果申请失败则返回FALSE;

2.ALLOC_NULL_MEM (char*pointer, MEM_TYPE memTypeint size) :申请一块内存给pointer, 并把这块内存清空;如果申请失败则返回FALSE;

3. ALLOC_CPY_MEM (char*pointer, MEM_TYPE memType int size, char*copyed_pointer) :申请一块内存给pointer, 并把指向内存copyed_pointer的内容复制到这个内存;如果申请失败则返回FALSE;

4. ALLOC_SET_MEM (char*pointer, MEM_TYPE memType int size, char set_code) 申请一块内存, 并设置这块内存为字符set_code;如果申请失败则返回FALSE;

5.ALLOC_CRIT_MEM (char*pointer, MEM_TYPE memTypeint size) 申请一块内存, 无返回值。如果不成功将产生assert和严重告警;

6. RET_MEM_NULLCHK (char*pointer) 释放一块内存, 并把原来指向这块内存的指针设置为NULL。另外在释放之前检查这块内存是否为NULL。从而避免了对内存的重复释放;

7.RET_MEM (char*pointer) 释放一块内存, 并把原来指向这块内存的指针设置为NULL。从而避免了野指针。

2.4内存释放和内存申请的原则内存方案

在使用内存的过程中, 我们总是不可避免地遭遇各种各样的内存问题 (除非程序足够短) 。基于生命周期的内存管理可以在一定程度上避免产生内存问题, 但不一定会消除内存问题。所以, 经过对程序大量的调试、测试, 提出如下几条内存使用原则:

1.为当前指针申请一块内存之前, 如果不确定当前指针是否为NULL, 应使用RET_MEM_NULLCHK进行检查。

2.为当前指针申请内存时, 要根据实际需求申请合适大小的内存, 避免内存浪费。

3.为临时变量申请内存时尽量使用栈内存。这样可以减少内存泄漏的危险。

4.在任务之间传递内存 (消息传递) 时, 这块内存应当只在接收到消息的任务中释放。

5、如果一个任务中的发送消息失败, 要释放掉所有与这个没有发送出的消息相关的内存。

6. 在函数之间传递内存 (指针传递) 时, 被调用的函数应当永远不能释放那块内存。要么, 调用函数应当通过某种方式告诉被调用函数, 被传递的内存应该被释放或者保留。

本文首先提出并详细阐述了基于生命周期的内存管理模型, 然后基于这种模型提出并论述了所设计内存类型以及自定义的内存API函数。最后, 提出了内存操作应注意的若干事项。

摘要:基于嵌入式实时操作系统VxWorks对内存的基本要求, 提出并实现基于VxWorks操作系统基于生命周期的内存管理的设计和实现。

关键词:VxWorks,任务管理,内存模型

参考文献

[1]罗国庆.VxWork与嵌入式软件开发[M].机械工业出版社, 2003.

[2]Wind River.VxWorks Programmer's Guide 5.5[EB/OL].

[3]Wind River.VxWorks Reference Manual:Libraries[EB/OL].

[4]何先波一种基于VxWorks的内存管理封装层的设计与实现西华师范大学学报2005.

一种基于哈希索引的内存表模型 篇2

随着企业应用系统的日益庞大和复杂,对于应用系统的灵活性、可扩展性要求也越来越高。为了能满足高灵活性、高可扩展性的要求,应用系统中采用了大量的参数配置设计。高度参数化的系统可以使得应用系统具有高度的灵活性和可扩展性,一些功能仅需要通过参数的配置就可以快速的实现。

高度参数化的应用系统在运行过程中,需要查询大量的配置参数,因此参数的存放与查询成为应用系统的重要组成部分。由于参数量比较庞大,为了维护和管理便利,应用系统的参数通常被存放在数据库中,应用系统在运行时通过使用SQL语句访问数据库的方式查询参数[1]。这种方式虽然实现简便,但是由于数据库本身的性能以及网络数据传输的消耗等因素,会影响应用处理查询参数的速度,从而降低应用系统的性能表现,因此通过直接访问数据库查询参数的方式比较适合于参数非常复杂、但是对应用系统的处理速度要求不高的系统。而一些对于处理速度要求非常高的系统,采用这种方式常常无法满足要求。本文尝试通过一种基于哈希索引[2]的内存表模型来解决高速应用系统中参数查询的问题。

1 技术方案

1.1 内存表建立

为了加快应用系统的查询,采用的是将参数缓存在共享内存[3]中的设计。根据参数表的张数、每一张参数表的记录数以及每一条记录的长度,计算出需要存储这些参数的内存大小。根据计算出的容量申请两块内存,每一块内存都包含控制信息段、数据表头索引段和表数据段三大部分。具体的结构如图1所示。

控制信息段中存放着本块内存的信息,包括内存编号、是否激活标志等。数据表头索引段中存放这每一张数据表的表数据段指针,指向表的首记录。表数据段中用于存放参数表的具体数据。在实际设计过程中,为了降低后续哈希计算时出现碰撞的概率,每一个表数据段的长度可以定为大于表记录数的最小质数。

1.2 内存表数据装载

从数据库中将数据逐表取出,顺序的存放在表数据段中,每一条记录占用一个记录单元。每一个记录单元分为数据区和索引区两部分。每一条数据存储在数据区内,待存储完后,对该条记录的查询主键进行哈希散列计算[4],获得一个哈希值。以计算获得的哈希值作为下标,定位一个记录单元,将该条数据与该表第一条数据之间的偏移填写入该记录单元的索引区index字段中。生成的索引若出现碰撞,则将偏移量存入索引指向的记录单元的next字段中,形成一个单向链表。若该记录单元next字段中已经存放之前发生碰撞的数据区偏移量,则根据next索引到下一个记录单元,直到寻找到链表的尾部,将本次装载的记录单元链接在链表的尾部。如图2所示。

图中数据一的哈希计算值为2,因此offset 2索引区的index1字段指向了数据一。数据二的哈希计算值为m,因此offset m索引区的index1指向了数据二。数据三的哈希计算值为2与数据一的索引值发生了碰撞,因此数据一的next指向了数据三,形成了一条单向链表。

在实际的设计中,可以根据查询的条件不同,为一张数据表生成另一个索引,索引值存放在Index2中。通过逐张数据表的逐条数据装载,在内存中就建立起了一张带有哈希索引的数据表。

1.3 内存表的使用

当应用系统需要查询数据时,通过判断控制段中的FLAG标志,来判断两块内存中,哪一块是当前激活的内存表。根据需要查询的表,从数据表头索引段中获取该数据表第一条数据的具体位置。

根据查询的主键,使用与装载时相同的散列算法对查询主键进行散列计算,从而获得待查数据的索引值。将索引值作为下标,快速的定位到索引区,根据索引区中存放的数据单元偏移,快速地定位到数据单元。数据单元的数据区数据取出后,将该查询主键与数据进行比较,若相同,则查询命中。若不相同,则检查该数据区的next是否指向下另一数据单元。若指向另一数据单元,则根据next中存放的偏移定位到下一数据单元继续比较,直到检索到数据或者检索到链表尾部。若该数据单元已经是链表尾部,则本次查询失败。

1.4 数据更新

应用系统运行中会面对参数更新的情况,为了保证内存表在进行参数更新时不影响应用系统的连续运行,本模型中使用了A、B内存表滚动更新的设计。

A、B内存表滚动更新,是指在建立内存表时,同时建立两块大小完全相同的内存用于存放数据,一块称之为A表,一块称之为B表。当数据装载时,首先对A表进行装载,在数据完全装载后,将A表的控制段FLAG置为可用标志,然后对B表进行装载,此时内存表已经可以提供查询功能。当需要进行参数更新时,首先将B表的数据进行更新,由于此时A表为可用状态,因此对B表的更新不会影响应用系统的查询。待B表更新完成后,将A表的控制段FLAG标志置为不可用,B表的控制段FLAG置为可用。此时应用系统的查询将改为在B表上进行,因此可以对A表的数据进行更新。整个数据更新过程中,总有一块内存表能够为应用系统提供查询服务,A、B表之间循环滚动的进行更新。更新的步骤可参见图3所示。

在进行内存更新时可以进行单个数据表的更新,或者整张内存表的更新。更新采用的是将整表数据重新装载的方式,这样可以将增删改统一采用整表装载的方式进行更新。但是若是增加数据,且增加后数据条数大于原内存表建立时计算的数据单元个数时,需要将整块内存表释放后重新建立。

2 结 语

本文旨在描述如何通过构建一个基于哈希索引内存表的模型来提升应用系统查询数据速度。基于应用系统的实际数据量和查询需求,我们对这个模型进行了扩充和完善,作为中国银联交换系统中高速参数缓存的解决方案。该方案实现了参数的装载、查询、更新,具备了较高的可用性、可扩展性和较高的处理性能。根据该模型实现的内存表模块将中国银联交换系统的主要运行参数缓存在内存中,供交换系统运行时进行数据检索。缓存的数据表约为70张,单表数据记录数最大可达百万级。通过内存表缓存后,数据检索性能较直接访问数据库检索有大幅提升,单条数据检索时间可缩短到毫秒级。

参考文献

[1]戴特.SQL与关系数据库理论[M].周成兴,译.清华大学出版社,2010.

[2]科曼.算法导论[M].潘金贵,译.机械工业出版社,2006.

[3]史蒂文斯,拉戈.UNIX环境高级编程[M].尤晋元,张亚英,戚正伟,译.人民邮电出版社,2006.

内存管理模型 篇3

1 概述

由于手机本来内存就少, 系统运行时间会很长, 并且极少重启, 内核、服务器以及一些应用程序运行几年, 即使电源关闭, 也需要保持某些应用的状态, 少量的内存泄漏经过积累也会造成灾难性的后果, 编写的程序必须是没有内存泄漏的。因此, 所有分配的堆内存必须至少有一个指针关联 (即使出现内存不足的情况) , 所有堆内存必须在使用完以后尽快释放。

Symbian OS采用不同于其他任何平台的独特机制来保证内存安全, 主要有以下三种:一是Trap harness (陷阱套) ;二是Cleanup stack (清除栈) ;三是Two phase construction (两阶段构造) 。我们必须熟悉上述三个机制, 以保证程序是内存安全的。

2 管理内存的三种机制

2.1 陷阱套 (Trap harness)

异常通常是运行时某种资源的缺少而引发的错误, 如内存不足或者通信端口不可用。我们要搞清楚错误和异常的区别, 错误是可以通过修改程序而消除掉的, 但是要确保程序不会产生异常几乎是不可能的。在Symbian中推荐采用Leave, 也就是抛出异常。如果内存或者资源不能分配到, 这个代码就会Leave (抛出异常) , 沿着Call Stack, 直到操作系统或者在某个函数中被处理。所有可能Leave的函数最好以L结尾, 保证该函数的用户知道这个函数可能Leave。程序发生异常时Leave, 会被上层调用中的TRAP捕捉, 例如:

如果异常时Leave, 将会返回到最近的一个TRAP Harness。在Symbian系统中出现了错误和异常, 要能够及时捕获并处理, 类似标准C++的CATCH。Symbian C++用TRAP或TRAPD关键字可以对一个可能产生异常的函数进行保护并捕获到异常值。这两个关键字的区别就在于TRAPD中声明了一个用于保存异常退出错误代码的变量, 也就是说, TRAPD不需要程序员自己设置参数, 而如果使用TRAP, 程序代码本身必须在调用TRAP前声明一个变量。需要注意的是TRAPD的嵌套以及同名变量的使用。下面我们看看TRAP和TRAPD关键字的使用。

我们在使用TRAP与Leave进行异常的捕捉和抛出时, 应该注意以下几点: (1) 将95%的错误上交给系统处理, 不要自己处理; (2) 如果不是自己处理所有错误信息, 则将错误用User:Leave () 或User::Leave If Error () 上传; (3) 在执行TRAP时, 都会导致内核执行调用, 并且还会分配一个结构体来保存异常退出发生时栈的内容, 所以使用TRAP代价较高, 尽量少使用或者替代使用TRAP, 会节省很多资源。不要连续使用多个TRAP, 而是利用方法Leave, 从而将错误交给调用者处理。

2.2 清除栈 (Cleanup stack)

清除栈用来保存分配在堆上的对象指针, 一旦出现异常, 系统能够通过清除栈释放出错程序在堆中分配的空间, 从而避免内存泄漏。

Symbian有一个Clean up stack, 在使用指针时, 用Push L把指针压入栈中, 使用完后再用Pop弹出栈, 如果在中间调用可能导致崩溃的函数时果真出现了问题, 那么Clean up stack可以通过调用该指针的析构函数回收占用的空间。这些可能导致崩溃的函数在Symbian里被称为可能Leave的函数, 所以就在这些函数的尾部加了一个L。而加LC后缀的函数表明该函数已经在内部把指针用Push L压入Clean up stack了, 调用时无需再用Push L, 直接调用完用Pop既可。Clean up stack还提供了一个Pop And Destroy函数, 就是弹出栈后再销毁指针。正是因为有了Clean up stack机制, 所以Symbian在有些地方看起来跟VC的程序不太一样, 比如说很多类的构造函数都不用, 用New L或New LC构造, 分配地址时的操作符new () 也变成了new (ELeave) 。

在这些场合应该用到清除栈, 在一个可能Leave的函数中产生的, 栈上指向C对象的自动变量指针要Push到清除栈中。一旦出现了异常, TRAP harness将调用Pop And Destropy () 来清空清除栈上所有从调用TRAP时压进去的变量, 并释放相应的堆空间。当不会出现Leave时, 需要将对象指针从清除栈中弹出。在我们进行开发的时候, 每个应用程序都有自己的清除栈, 其中控制台程序 (.exe) 需要在E32Main中声明, 代码如下:

GUI程序由CONE创建, 因此不需要我们自己创建。

在使用清除栈时, 类的成员变量不用放在清除栈中, 否则会造成多次删除, 也就是说如果放在了清除栈, 将会在类的析构函数中删除一次, 在退出清除栈时又被删除一次。

不要在TRAP和TRAPD宏中使用LC结尾的函数, 因为在TRAP宏里面标记了清除栈, 它会自动调用传入的函数, 并且它希望在函数调用结束后, 函数能够把清除栈中的所有本次调用产生的对象都弹出。而LC结尾的函数将向清除栈压入一个生成的对象, 该对象应该由该函数的调用者弹出, 因此当我们使用TRAP/TRAPD宏调用以LC结尾的函数的话, 在调用结束后清理栈中仍然有一个对象不能够被销毁。这样就会引发E32User Panic 71的严重错误。

使用TRAP/TRAPD宏和创建清除栈并不是编程所必须的, 如果开发过程中没有使用到任何公共资源 (不会造成Leave或者异常的操作) , 那么完全可以不必理会这些宏和清除栈。

2.3 两阶段构造 (two-phase construct)

两阶段构造是Symbian OS中特有的构造方法。当在堆上进行实例化对象时, 构造函数将被调用。如果在构造过程中发生异常退出, 就会导致内存泄露。为了确保构造函数绝对不发生异常退出, Symbian将构造这一过程分为两阶段进行。第一阶段在堆上分配一个对象, 执行不会异常退出的最基本的初始化工作, 将任何可能异常退出的代码放在第二阶段进行。在进行第二阶段构造前, 首先将对象推入清除栈, 如果异常退出, 清除栈会释放对象。具体实现如下:

在第一阶段构造中, 只执行最基本的初始化任务, 任何可能异常的工作全在第二阶段完成, 在第一阶段构造中不会出现Leave。否则就有可能出现错误, 这对于智能手机来说是绝对不允许的。因此, 在第一阶段构造中不能访问任何资源, 例如内存、通信端口等。

在Symbian内存管理的这三种机制中, 我们主要使用TRAP Harness来处理Leave的异常, 使用Cleanup Stack来保存本地的堆指针, 使用两阶段构造来创建复合对象。

3 结束语

我们在基于Symbian OS进行开发的过程中, 还要注意很多细节以保证内存安全, 例如:C类必须有析构函数, 这是CBase的一个虚函数;C类的构造函数和Construct L () 必须为protect或private类型的成员函数;拷贝构造函数在Symbian中没有用;不一定在析构函数中删除类的成员对象, 生命期结束即可删除;尽可能早地删除一切失去使用价值的东西, 不要等到函数尾部 (自动变量) 或在析构函数中才删除 (成员变量) 等等, 这些都是要求我们在开发过程中加以注意的。

参考文献

[1]蔡鹤亭, 朱立.电子政务绩效评估的AHP-Fuzzy模型与案例[J].信阳师范学院学报 (自然科学版) , 2007 (3) .

[2]金纯, 过晓华.基于Symbian OS的蓝牙网络聊天系统[J].微计算机信息, 2007 (24) .

[3]姚盛旺.Symbian OS C++程序开发[J].计算机与数字工程, 2007 (1) .

[4]钮雪莲, 凌力.Symbian系统平台安全性设计分析与改进[J].计算机工程, 2006 (11) .

计算机内存管理技术研究 篇4

1 计算机的存储介质

计算机中用于信息存储最多的工具就是软盘、硬盘与电子盘, 这些磁盘又被统称做非易失性存储器。一般情况下我们了解最多的内存, 指的是易失性较强的。可是芯片的读取速度相对于磁盘而言要快得多, 一般磁盘的读取速度在20毫秒至100毫秒之间, 但是芯片的速度却是磁盘的100万倍以上。现如今在工业控制的过程中, 有部分厂家使用的是电子盘进行数据的记录, 而在某种特定的情形下, 也就是出现了大量的告诉运行的数据的情况下, 很容易造成数据的丢失情况出现。假如使用的是芯片内存, 那么问题就很容易解决了。这是因为芯片内存的存储, 就像是中央处理器在工控机的内存之间的读写工作, 其操作速度一般在电子盘之上。PC机的中央处理器类型各不相同, 而且地址线也不太一样, 所以找寻地址的能力也存在差别, 中间的内存空间同样也是不一样的。详细数据可参见表1。

2 windows XP对内存管理以及其具体使用环境的优化改善

2.1 内存的一般理念

内存指的是计算机在运行的过程中存储的相关文件、使用程序以及数据的仓库等等。PC机内存能够将其分成基本内存、上层内存区、扩展内存、高内存区以及扩充内存几个方面, 其具体的含义内容是:

基本内存:其是PC级内存中占据前670KB的内存, 是通过windows进行直属管理, 所有的建立在windows基础上的软件全部都要使用基本内存。

上层内存区:区间是在640KB至1MB之内的384KB, 当中的windows中保留的部分范围内的对计算机的硬件进行供应过程使用, 上层内存区中没有使用的空间被统称为上层存储区块, 其在386以及486当中, 能够将扩展内存的范围内部分内存反映到这个区域之中, 其使用在运行设别的驱动程序和内存的驻留程序之上。

扩展内存:是在计算机1MB以上的内存, 在这一部分的内存使用, 需要建立在有扩展内存的环境条件管理下才能够使用。

高内存区:其是扩展内存之中的前面64KB内存, windows能够在这样一个区域内完成工作。

扩展内存:在早期的PC机之中, 会把1MB以上的内存分页反映使用在上层内存区之中的64KB空间范围之内做使用操作, 这样一个部分的内存整体性的被叫做扩充内存, 在386以及486计算机之中使用的是EMM386把扩展开的内存仿真成为扩充内存进行持续性使用。

图1中描述的就是一部典型的4MB的内存计算机的配置形式, 因为过去发展的原因, 很多的建立在windows XP系统上的应用软件只能够进行640KB内容的使用, 而且windows自身以及相应的操作设备驱动程序和内存的驻留程序能够占据一部分的基本内存, 所以伴随着应用软件的使用逐渐复杂深入起来, 在640KB的基本内存现如今的面临的问题就是使用。除此之外在windows XP中供应的一个文件, 能够自行自动修正, 使其保持在最佳的状态之下。

2.2 设置高内存区以及扩展内存区的相关指令

要想使用1MB以上的内存需要解决的问题有两方面, 分别是, 第一, 计算机需要有1MB以上的内存扩展, 此项条件只有在286以上的计算机才拥有;第二, 需要有专门的设备驱动程序将其扩展成内存的前64KB使其作用在高内存的管理区域中, 例如程序HIMEN.SYS程序。

3 内存管理技术研究

3.1 内存管理需求的提出

计算机的使用上, 内存管理是一个最重要的工作管理环节。内存管理模块中包含的内容有对应运行系统的代码段、数据段以及堆内存的管理和虚拟地址以及物理地址之间的互相转换功能等等。但是, 在可靠性和安全性要求较高的环境中, 单纯的有上文中提到的几点内容还是远远不够的。C语言中供应的是动态式内存, 其互相分配机制虽然在程序运行中带来了巨大的灵活性和便利, 可是同时又和有一些潜在的危险存在。但是在军事、航天以及通信应用等等工作方面中, 整体的系统运行是长期进行的, 而在这样的情况之下, 因为内存的泄漏而带来的危害是巨大的, 其会使得程序的整体运行效率出现巨大的纰漏。更为严重的情况就是, 整个操作运行系统可能会因为消耗尽内存的原因而完全崩盘。因此系统中使用的是动态的内存跟踪和分析式的方法对内存的泄漏进行检查, 并且在任务结合的过程中重新检查一遍在堆中的任务动态内存还有没有残余, 如果发现内存泄漏的情况, 那么系统的运行将会被完全释放。

针对计算机要求较高的嵌入式场合, 例如航天和军事, 对其的可靠性要求更高。为了能够保护某些相对重要的数据, 在SROS内核中需要使用的分配方法是内存冗余的形式, 能够让这些数据在整体的运行系统中能够多复制几份。而在某些较恶劣的工作环境中, 像是太空中, 因为会收到来自宇宙中的射线电磁的干扰, 有可能会造成内存中的某些数据出现逆转和将数据破坏掉。所以, 内核中供应了内存差错编码对错误情况进行检查和校准。

因为使用的SROS内核使用的内存模式是平坦型的模式, 也就是线性地址和物理地址之间是互相对应的, 因此内核与各个操作任务之间都能够较便利的获得其他模板上的数据段以及代码段等等。在这种形式的情况之下, 就很难确保数据的安全性了。因此整个系统使用的是以MMU为基础的内存保护办法, 对系统的不连续性进行数据保护, 只通过用户对自身的堆栈段的任务访问要求, 不能够越过等级去访问其他的任务堆栈段内容。

3.2 内存扩充的访问方式

一般情况下, 在windows情况下使用内存扩充的方式包含了三个方面, 分别是第一:利用BIOS截止的INT15H, 此项操作方法能够让系统在短时间内处于被保护状态, 在数据传输完成后能够实现返回模式的建立。此项方式属于一种较低端的方式, 不能够控制扩充的访问内存, 同时存在好几个应用程序使用在扩充内存的工作中时, 彼此之间可能会出现互相矛盾的作用;第二, 使用停止的87H, 此项操作方式使用的是扩充内存模拟扩展内存的形式, 能够把系统保持在内存中国的一个操作页面, 并将其反映至扩展内存之中。扩展内存属于中央处理器直接寻址区域以外的一种内存, 其不是安装在系统的主板之上, 而是安装在扩展内存卡上。这项操作办法对于扩充内存的访问不是毫无限制的, 彼此的应用程序没有太大的冲突, 可是单纯的只能够寻址32MB, 而且每次的数据传输只能够保持在64KB左右, 实际的使用情况十分的不容易;第三, 使用中断的2FH, 能够有序的实现扩充内存和常规内存之间的数据传输。此项操作方式的寻址范围控制在4GB左右, 并且每一次的数据传输都能够保持在4GB的大小, 其对于内存能够进行直接的访问, 而且也会受到相应的控制。一般情况下使用的是第三种方式进行XMS的访问工作, 从而有效的而避免在windows处理过程中因为中断而造成的各项问题。

3.3 计算机最新存储介质技术

FB-DIMM, 也就是全缓冲内存模组, 其是从Intel、DDR2以及DDR3基础上发展而来的全新的内存模组以及互联网架构, 不但能够配合现在使用最多的DDR2芯片, 同时也能够派和未来的DDR3内存芯片, 能够最大程度的提升系统内存中国的带宽以及提升内存的最大存储量。和现在的一般DDR2内存相比较, FB-DIMM的优势还是十分明显的。内存频率一致的条件下, 能够有至少四倍以上的内存带宽, 而且能够有效的支持最大的内存容量, 同样能够完成普通内存的24倍, 一般情况下系统能够最大程度的支撑192GB的内存[5]。

但是从更为严格的角度分析, FB-DIMM还无法算作是最新的内存方式, 其只是一种有较大的提升空间的内存连接技术, 其中并没有包含内存的核心性技术, 其只是利用了现在存在的DRAM芯片, 并且在系统框架和互联形式上进行了全新的创新。

4 结束语

PC机的迅速发展的一个重要的标志内容就是内存容量的加大, 因为历史的原因单纯硬件的加大是无法满足数据的储存和分配要求把的, 因此必须要有一个与之对应的管理软件对其开展管理工作, windows XP及以上的版本会对内存的管理实行科学客观的分区操作, 这就加多了使用不同区之内的内存设备驱动设施。在CONFIG.SYS的文件中选择这些用于驱动的设备和程序, 那么整体运行操作体系完全启动之后, 出现的运行环境会是最为理想的, 其能够让用户获得更多的内存空间, 与此同时, windows XP及以上的版本内容在配置系统文件的过程中能够加入较多的辅助性指令, 同时能够使用系统配置菜单的操作模式为用户供应更多种形式的选择配置, 当一项合理有效的辅助命令作用在配置菜单的过程中, 用户能够在启动的过程中进行不同配置的选择。

摘要:计算机的使用范围不断拓宽, 伴随着操作系统的逐渐复杂化, 在运行过程中需要收集的数据越来越多, 并且需要及时有效的了解清楚系统的整体运行形势。如何将庞大的数据用更灵活的方式运行, 成为计算机应用中亟待解决的问题。建立在工控机的基础上, 用来解决逐渐加多的数据在长时间内的高速运转储存的方式, 分析研究关于IBM-PC机扩展内存建立在windows操作系统下完成直接访问的路径, 使用C++语言以及汇编语言完成编程工作, 最大程度的将C++类以及对象的特点发挥出来, 编制出一个能够在windows操作系统下的64MB以及128MB内存共同存在的有自动卸载能力的全新的操作系数, 在实时高速数据的收集操作体系中, 具有良好的使用性能。

关键词:内存,访问方式,保护,管理技术

参考文献

[1]戴明桢, 周建江.TMS320C54XDSP结构、原理及应用[M].北京:北京航空航天大学出版社, 2009, 02 (04) .

[2]楼永红.面向嵌入式实时应用的内存管理技术研究[J].浙江大学.2012, 05 (13) .

[3]石坚, 雷咏梅.面向TD协议栈的内存管理技术研究[J].计算机技术与发展.2009, 11 (19) .

[4]Van Wolverton.Running MS-DOS 20th Anniversary Edition[M].Microsoft Press, 2012.

数据库服务器内存管理 篇5

现有大型应用系统都离不开数据库服务器,一旦因为数据库内存不足,就会引起登陆失败或死机现象,导致业务系统无法正常运行。因此掌握数据库服务器内存管理是现有IT维护工作的重要一环。目前服务器使用数据库管理软件种类很多,但其基本原理与特点都很类似。本文以ASE服务器为例,以数据库内存管理中常用的最大用户连接数,打开数据库、索引、目标数,数据库设备数等各类事件,来简单介绍如何对数据库服务器内存进行有效管理,保障业务应用的正常运行。为了掌握数据库服务器内存管理,我们必须先了解一些基本概念,以便掌握分配和估算内存使用的一般方法。下文的说明是以数据库服务器ASE为依据给出的。

2 服务器内存分配的构成

如图1所示,物理内存(Physical Memory)是指安装ASE服务器的服务器物理内存。为了查看服务器的物理内存,在操作系统提示符后用top命令(如果使用Unix操作系统,在操作系统提示符后用top命令,在Windows系统平台时用mem命令)可显示服务器的物理内存。最大内存(Max Memory)是指物理内存中用于ASE服务器的最大内存,即最大内存为能被ASE服务器使用的最大共享内存。最大内存越大服务器运转得越好。Adaptive服务器操作系统(ASE Executable)内存被用于运行服务器的操作系统。这块内存是不可配置的,其余内存则为内部结构内存和存储器内存。核心结构内存(Kernel Structure)用于在ASE服务器运行期间存储内部信息。服务结构内存(Server structure)用于存储关于用户连接数、在用数据库、有效的数据库锁定等信息。内存对象池(Memory Object pool)是一个从中可以动态地选择分配较小的存储段的存储块。数据存储器(Data Cache)是存放当前在用的数据页、索引页和日志页的ASE服务器内存块,如图2所示。当数据页、索引页和日志页在用时,它们被存放在数据存储器中,而没被ASE使用的数据页、索引页和日志页则存放在硬盘上。我们可以使用sp_cacheconfig过程来配置数据存储器的大小,例如:

1>sp_configure"default data cache",“1000M”

2>go

过程存储器(procedure cache)是ASE存放当前在用查询方案(query plan)的内存块(见图3),我们可以使用sp_configure过程来配置数据存储器的大小,例如:

3 设置数据存储器和过程存储器能减少读写硬盘的频率

为了认清数据存储器和过程存储器的作用,我们先分别了解数据页、索引页和日志页(以下简称数据页)是如何通过数据存储器以及查询方案如何通过过程存储器。数据页通过数据存储器的过程如图4所示,当一个修改数据的语句被执行时,服务器首先把要被修改的相关页拷贝到数据存储器中(如果此页已经在数据存储器中,则服务器不需要访问硬盘及拷贝数据页)。其次,数据存储器中的数据页按需要被操作,如修改等。当数据存储器没有足够的空间存放新的数据页时,其中的某些旧的数据页就会被从中去掉,即数据存储器的数据页过期。当数据存储器中的一个数据页过期(从数据存储器中去掉)前,其中的改变内容会被保存到硬盘。如此的数据读取存盘机制降低服务器对硬盘的访问频率。查询方案如何通过过程存储器的过程如图5所示,当一个存储过程语句被执行时,服务器首先从系统表sysprocedures中生成查询方案并存放到过程存储器中(如果此查询方案已经存在于过程存储器中,则省略此步骤)。其次,过程存储器中的查询反方案被使用。当没有足够的空间容纳新的查询方案时,过程存储器中一些查询方案会过期,被从过程存储器中去掉。从数据页通过数据存储器的过程不难看出,数据存储器的使用减少了对硬盘的读写操作。从查询方案通过过程存储器的过程不难看出,过程存储器的使用减少了生成查询方案的操作。可见,数据存储器和过程存储器的使用优化了服务器的运行。

4 使用内存的估算

判断内存占用情况,包括判读哪一方面内存占用较多,这些内存占用是否合理,是否影响了服务器的正常运行。从以上的简要介绍我们可以了解服务器物理内存的分配情况(见图1)。很明显,有一部分内存占用是不可改变的,如操作系统和其他程序占用、Adaptive服务器操作系统占用,因此,我们主要考虑其他可以变动的占用。为了能清楚地估计服务器内存占用,我们有必要介绍服务器内存占用的几个典型的方面,包括最大用户连接数,打开的数据库、索引、锁的数目,数据库设备数,数据存储器和过程存储器等。以下将对这些方面具体介绍并举例说明如何估计其占用内存的大小。

我们知道,每一用户连接都要耗费内存,因此定义最大的用户连接数对内存有影响。我们可以使用number of user connections参数来配置用户的连接数,例如:

其中,配置的用户连接数(Run Value)为50,对应此用户连接数耗费的内存(Memory Used)为12742(以2K为单位)。

为了更好地管理内存,服务器提供用于提供估计耗费值的语句,格式为:

sp_helpconfig"参数","值"

其中“值“可以是参数值,也可以是内存值。当“值”为参数值时执行结果能显示该参数值耗费的内存,当“值”为内存值时可以返回使用这些内存要使用多大的参数配置值。例如:

这表示要使用“50M“内存,应该配置的用户连接数为200个用户连接。

当服务器打开数据库、索引、目标时,它需要从对应的系统表中获得信息。这些信息被复制到内存的存储器中,这样可以避免对硬盘的频繁访问。我们可用对应的过程使用来配置或者查看参数和内存,以下具体举例说明。

配置打开数据库数目的情况:

此配置将打开数据库的数目为12,这时耗费的内存为1490(以2K单位)。

配置打开索引数目的情况:

此配置将打开索引的数目配置为10000,这时耗费的内存为12030(以2K单位)。

配置打开目标数目的情况:

此配置将打开索引的数目配置为10000,这时耗费的内存为14437(以2K单位)。

配置使用锁数目的情况:

此配置将使用锁的数目为100000,这时耗费的内存为14862(以2K单位)。

配置使用数据库设备数量的情况:

此配置将使用数据库设备数量为50,这时耗费的内存为#28(以2K单位)。其中的#代表此内存是包含在另一个参数内存中的。

5 分配服务器内存的步骤

有了以上对内存使用的认识,我们就可以进一步规划服务器的内存。给定一台服务器作为数据库服务器,我们如何为其配置内存的分配呢?服务器内存的总体分配如图1所示,分配过程可按以下步骤进行:首先要确定最大内存,确定最大内存是通过物理内存减去操作系统和其他应用程序(此服务器可能使用其它应用程序)所占内存得到的,而物理内存可用top(对于Unix系统)得到。其次要确定服务结构所占内存,此内存是通过估计用户连接数、打开数据库数、打开索引数、打开目标数、锁数目、建立数据库设备数等占用内存的和得到的。在设计完成并使用后也可根据错误日志的指示重新调整配置参数。第三,确定数据存储器和过程存储器的大小。第四,配置完成后启动服务器。在启动时,服务器先检查是否有足够的内存支持配置,没有足够内存则失败,需根据错误日志指示重新配置,有足够内存则依次分配服务器操作系统内存、核心结构内存、服务结构内存、数据存储器和过程存储器内存。在启动过程中,分配内存的日志会被写到错误日志中。第五,根据错误日志的情况确定该修改或调整哪些日志。

6 结束语

内存管理模型 篇6

关键词:计算机软件,内存管理优化,综述,安卓,Java虚拟机

0 引言

android操作系统是Google公司发行的基于Linux的开放源代码操作系统。当前针对android的应用都是基于Android的Dalvik虚拟机[1]开发的。Dalvik虚拟机本身为应用程序提供默认的内存管理支持。但由于Dalvik虚拟机功能的局限性,以及系统本身针对每个Dalvik虚拟机最多只分配24M的堆空间。因此,如果工程师对Android的内存管理机制不了解,容易造成系统的OOM[2](out of memory)错误。

内存管理,是指程序运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何为进程高效快速的分配,并且在适当的时候释放和回收内存资源。一个执行中的程序在内存中主要包括代码区和数据区,以及操作系统为该程序分配的系统各种资源。操作系统对内存管理的机制直接影响程序读取数据的速度,从而间接影响程序执行的速度。如果程序执行过程中出现OOM等内存错误,用户的个人配置数据会处于不确定状态。Android操作系统多用于内存较小的手机客户端,并且提供对多个进程提供内存管理功能。

综上所述,了解Android内存管理对工程师是至关重要的。

1 Android系统对内存管理分析

1.1 Android对内存管理的整体架构综述

Android采取了一种有别于Linux的进程管理策略[3]。Linux的在进程活动停止后就结束该进程。而Android会把这些进程都保留在内存中,直到系统需要更多内存为止。这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度。

首先介绍android程序分类:

(1) foreground:正在屏幕上显示的进程和一些系统进程。

(2) visible:可见进程是一些不再前台,但用户依然可见的进程,例如widget、输入法等,都属于visible。

(3) secondary server:目前正在运行的一些服务(主要服务,如拨号等,是不可能被终止的)。

(4) hidden:启动后被切换到后台的进程,如浏览器。后台进程的管理策略有多种:有较为积极的方式,一旦程序到达后台立即终止,这种方式会提高程序的运行速度,但无法加速程序的再次启动;也有较消极的方式,尽可能多的保留后台程序,虽然可能会影响到单个程序的运行速度,但在再次启动已启动的程序时,速度会有所提升。

(5) content provider:没有程序实体,提供内容供其它程序去用的,比如日历供应节点,邮件供应节点等。在终止进程时,这类程序应该有较高的优先权。

(6) empty:没有任何东西在内运行的进程,有些程序,比如BTE,在程序退出后,依然会在进程中驻留一个空进程,这个进程里没有任何数据在运行,作用往往是提高该程序下次的启动速度或者记录程序的一些历史信息。这部分进程因该是最先终止的。

Android系统决定结束进程的依据:

(1)系统会对进程的优先级进行评估,将优先级以“oom_adj”这个数值表示出来.一般来说,“oom_adj”的值越大,该进程被系统选中终止的可能就越高。

(2)前台程序的“oom_adj”值为0,这意味着它不会被系统终止,一旦它不可访问后,会获得个更高的“oom_adj,一般“oom_adj”的值是根据软件在LRU列表中的位置所决定的。

(3) Android有一套自己独特的进程管理模块,这个模块有更强的可定制性,可根据“oom_adj”值的范围来决定进程管理策略。

综上所述,Android系统在选择退出程序时,并不是完全退出程序,该程序仍然会在后台驻留一个进程,以便下次更快的打开。系统会给每个类型的程序一个内存值阈[4](阀门),当运行内存低于某个值时,系统会自动按照打开的先后顺序来关闭该类型的程序。例如,当内存小于24MB时,系统才会自动关闭空进程这一类型的程序,释放出更多的内存来供新程序使用,已保证新开程序的正常运行。

1.2 Dalvilk虚拟机内存结构

从图1中可以看出,运行时区主要下面由5个部分组成:

Method Area:被装载的class的元信息存储在Method Area中,它是线程共享的。

Heap(堆):一个虚拟机实例中只存在一个堆空间,存放一些对象信息,它是线程共享的。

Java栈:虚拟机直接对java栈进行两种操作,以帧为单位的压栈和出栈(非线程共享)

程序计数器(非线程共享)。

本地方法栈(非线程共享)。

Dalvik虚拟机把对象分为Young、Tenured、Perm,对不同生命周期的对象使用不同的垃圾回收算法。

Young:分为三个区,一个eden区,两个Survivor区。程序中大部分新的对象都在Eden区中,当Eden区满时,还存活的对象将被复制到其中一个Survivor区,当此Survivor区的对象占用空间满了时,此区存活的对象又被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到Tenured中。

Tenured:存放的是Young复制过来的对象,也就是在Young中还存活的对象,并且区满了复制过来的。Tenured中的对象生命周期都比较长。

Perm:用于存放静态的类和方法,对垃圾回收没有显著的影响。(如图1)

2 Android内存管理的缺点

1) Android针对每个应用程序启动一个独立的虚拟机,因此造成较大的内存消耗。

2) Android对已经关闭的进程并不立即回收内存,容易造成内存不足。

3 Android内存管理的优点

1) Android的应用在被切换到后台时,它其实已经被暂停了,并不会消耗CPU资源,只保留了运行状态,相对于Linux操作系统对内存的消耗更小。

2)允许设定内存调度的阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西,增加系统灵活性。

3)为每个应用打开一个独立的虚拟机,避免虚拟机崩溃导致整个系统崩溃。

4 针对Android应用程序的优化策略

1)应该尽量避免static成员变量引用资源耗费过多的实例,比如Context。

2) Context尽量使用Application Context,因为Application的Context生命周期比较长,引用它不会出现内存泄露的问题。

3)用弱引用代替强引用。

4)将线程的内部类,改为静态内部类。

5)在线程内部采用弱引用保存Context引用。

6)对于比较耗内存的Bitmap对象,需要及时销毁。

参考文献

[1]Jin T Y.Research of Android Architecture[M].Beijing: Posts & Telecom Press,2012

[2]Deng F P.Research on Android[M].Beijing:China Machine Press

[3]Li N.Director of Android Developer[M].Beijing:Posts & Telecom Press

[4]Yu Z L.Google Android SDK Application[M].Beijing: Posts & Telecom Press,2012

[5]Li M H.Introduction to Memory Management[OL].[2012]. http://android.mybdqn.com/kt/5414/

[6]Liu B L.Memory Leak in Android[OL].[2012].http:// www.apkbus.com/android- 71944-1 -1.html

[7]Marko Gargenta.Learning Android[M].Publishing House of Electronics Industry,2012

内存管理模型 篇7

Android是Google公司发布的基于Linux的操作系统,由系统内核、本地库和运行环境、应用程序框架层和应用程序四大部分组成,其中,Android 3.0系统内核在进程调度、文件系统、内存管理、设备驱动等方面都有很大改进,本文集中剖析了Android 3.0内存管理在Linux 2.6内核基础上所作的改进。

1 Android内存管理的基本框架

1.1 Android对线性地址的组织

Android对线性地址的组织使用的是32位线性地址,编程使用的时候无需考虑物理地址,因为线性地址转换成物理地址会由称为分页单元的硬件电路完成。32位可以形成4GB的线性地址,Android把4GB的线性地址分成两部分,最高1GB为内核的专用空间,用户只能通过系统调用去访问内核,低位的3GB为内核和用户都可访问的空间[1],线性地址的组织如图1所示。

1.2 Android对物理空间的组织

无论是内存空间还是磁盘空间,都以页为单位组织。一般移动设备使用NAND Flash,因此对于磁盘空间Android使用了YAFFS2文件系统,对于内存空间就源用了Linux的管理方式,但由于现代技术的限制,移动设备上使用的RAM远达不到理论上32位可达到的4GB寻址范围,而在Android启动的时候会自动检测可利用的物理地址,因而Android只用到两个管理区:ZONE_DMA(0MB-16MB),ZONE_NORMAL(16MB-896MB)[2]。在运行过程中,Android各项主要的内存操作都源用Linux的处理方式,包括虚拟内存映射到物理内存进行页式映射、内存的分配和回收最终使用slab机制。

2 Android 3.0内存管理方面的新技术

Android 3.0内核在内存管理方面相对于Linux 2.6进行了多方面的改进,特别是针对连续大内存页,都是为了使Android更好地运行在移动设备上,下面介绍一些主要的改变。

2.1 Low Memory Killer

系统运行过程中会定时的检查内存使用情况,当发现空闲页框数低于某一预先设定的临界值lowmem_minfree的时候,就会调用LowMemoryKiller(),选定一个进程,强行删除并释放页框,其中的lowmem_shrink()函数实现选择一个进程,被选进程满足:(1) oom_adj最大(进程优先级最低)并且大于预先设定好的lowmem_adj相对应的等级;(2) 占用物理内存最大,for_each _process()函数扫描系统中的每一个进程,根据以上准则挑选出一个进程,最后调用force_sig()函数把删除该进程的信号发送到内核,完成进程的删除。

当系统内存低于临界值的时候,Android删除的标准只是根据oom_adj和该进程所占用的物理内存大小,这样的标准过于简单,虽然系统启动的时候已经确保Init进程不会被删掉,但是避免不了在运行的过程中,系统停止一些重要的进程,譬如有Root特权的进程、直接访问硬件设备的进程和其他内核线程,就是因为删除进程的随机性,会导致系统运行的不稳定。

2.2 PMEM

PMEM用于向用户提供连续的大尺寸物理内存共享空间,使DSP、GPU、VPU等设备可以更好地在Android上工作,该驱动有两种工作模式,(1) no_allocator模式:指PMEM的共享物理内存是以一个整体去分配;(2) allocator模式:指PMEM的共享物理内存被分割成多个小块进行。PMEM通过pmem_info,pmem_data,pmem_region_node三个结构体去实现和维护大尺寸内存共享空间,pmem_info代表一块PMEM设备分配的共享内存块,pmem_data表示pmem_info内存块的一个子块,这是PMEM allocator模式分配内存块的基本单位,pmem_region _node把每个pmem_data分成多个区域,pmem_info里每个分配出去的页面entry都会与不同的pmem_data有对应关系,三者的关系如图2所示。

相比于Linux在大连续物理内存分配时所使用的伙伴算法,Android采取了另外一种分配方式,在allocator模式下,pmem_allocate()采用最佳适应算法(bestfit)对内存位示图(bitmap)进行挑选[3],通过PMEM_IS_FREE()函数对要求扫描的内存块区域进行逐块对比,然后每次更新best_fit变量,循环结束后best_fit就是记录着最小的能适合所要求内存空间的内存块。

实现内存共享时,一个进程先打开PMEM,获得PMEM_ ALLOCATE分配到的内存块,成为master进程,并修改pmem_data->flags为PMEM_FLAGS_MASTERMAP,另外的进程再打开这个PMEM设备,分配到另外一个pmem_data,成为client进程,调用pmem_remap()和pmem_connect(),把master pmem中的一段或者是全部重新映射到自己的进程空间,从而实现共享。

PMEM采用最佳适应算法(bestfit)挑选最适合所要求内存空间的内存块,但这样每次分配后留下的都是最小的页内空间,整体来看这种算法会导致页内碎片的增多。

共享内存块提供了在任意数量的进程之间进行高效双向通信的机制。虽然每个使用者都可以读取写入数据,但是所有程序之间必须达成并遵守一定的协议,以防止诸如在读取信息之前覆写内存空间等竞争状态的出现。然而Android无法严格保证提供对共享内存块的独占访问。

2.3 ASHMEM

ASHMEM(匿名共享内存子系统)能够辅助内存管理系统来有效地管理内存。在Android内核中,当系统内存紧张时,内存管理系统就会进行内存回收算法,将一些最近没有用过的内存换出物理内存去,这样可以增加物理内存的供应。因此,当内存管理系统进行内存回收时,就会调用这里的ashmem_shrink函数,让Ashmem驱动程序执行内存回收操作;ASHMEM源用了Linux的mmap映射,通过调用shmem_file _setup(),从基于内存的文件系统tmpfs中创建一个文件给ashmem_area使用,并且把分配到的内存映射到进程空间,从而实现进程共享。对于所分配的共享内存空间,ASHMEM提供了PIN/UNPIN机制进行回收,PIN/UNPIN通过扫描ashmem_area->unpinned_list,找到与所请求内存块相符合的页框并进行锁定/解锁,最终当需要回收内存的时候,Android就会根据LRU原则对ashmem_range->lru链表上的页框进行回收。

3 改进研究

3.1 低内存页面回收标准

对于选定被删进程标准应该多元化,譬如综合考虑内存消耗量,如CPU时间、存活时间、oom_adj等值进行综合评分。

3.2 低内存机制的作用时间

因为LowMemoryKiller可能会引起系统其他程序的死亡,而且系统隔一段时间就对内存区进行检查,所以该机制更不能轻易使用,为了避免这个机制的敏感性,可以在task_struct添加一个警告器(可以算是一个计数器),当选定了一个进程后,并不马上执行删除,而是进行黄牌警告(修改该计数器),下次扫描到该进程累计两次黄牌警告(计数器修改到2的时候),才运行LowMemoryKiller删掉该进程,数据结构如下:

struct task_struct{

unsigned int count;

……

}

4 后续研究方向及总结

Android 3.0的内存管理部分所做的改进远不止本文提到的,还有许多虽小但非常重要,后续研究的方向:(1) PMEM两种分配模式的运作机制;(2) 内核与进程空间是如何通信,从而实现共享;(3) PMEM不受标准Linux内核管理机制的管理[4],是否存在安全隐患。

总结:Android稳定性和性能方面都表现得不错,为移动设备提供了更好的支持。同时,Android 的使用范围也在不断地扩大,未来如何设计更好的内存管理系统仍然有一条漫长的道路要走。

摘要:Android是当代移动设备上运行的最流行的操作系统之一。Android 3.0基于Linux 2.6内核版本并在各方面都作了很大的改进,针对Android内存管理,剖析了3.0版本使用的新技术,同时提出了改进的途径。

关键词:安卓,内存管理

参考文献

[1]谢长生,刘志斌.Linux2.6内存管理研究[J].计算机应用研究,2005,22(3):58-60.

[2]Daniel P Bovet,Marco Cesati.Understanding the Linux kernel[M].Southeast University Press,2006.

[3]汤小兵.计算机操作系统[M].西安:电子科技大学出版社,2009.

上一篇:全国大学生英语竞赛下一篇:营销模式选择