荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: zzt (我命由我不由天), 信区: Program
标  题: 解决内存瓶颈问题
发信站: BBS 荔园晨风站 (Sun May 23 16:54:05 1999), 转信


发信人: mayanyi (▓▓※中坚分子※▓), 信区: Program
标  题: 解决内存瓶颈问题
发信站: 网易虚拟社区 (Wed May 19 01:43:45 1999), 站内信件

解决内存瓶颈问题
发信人: wql.bbs@bbs.swjtu.edu.cn (晖), 信区: dos
标  题: 解决内存瓶颈问题
发信站: 锦城驿站 (Thu Jun 26 22:19:33 1997)
转信站: xmucs!sjtunews!swjtunews!swjtubbs
Origin: xnjd21.swjtu.edu.cn
上海交大BBS供稿


摘要:本文用面向对象的程序设计方法,实现了对扩展内存和扩充内存的管理,
 从而能够以对用户透明的方式使用扩展内存和扩充内存,较好地解决大型软件中
的内存资源瓶颈。

一、问题的提出
   由于面向对象化编程的动态链接的特点,用C++完成的DOS 程序往往代码比较
庞大,占用内存空间较多。而在程序运行过程中,分配大量内存存储数据是在所
难免的。故常规内存资源十分紧张。尤其在大型的软件运行过程中,一旦内存不
够使用,将大大影响软件的可靠性。因此,有必要在保证内存资源方面找出较好
的方案,提高软件的性能。
    从当前的国内情况来看,大部分微机都配有 4 兆以上内存。 如果全部加以
利用,软件的内存资源基本上就可以解决了。在利用这部分内存的方案上,有以
下几种:

    ① 用 80286/80386 保护模式访问。
    但这个方案无法被所有的编程人员接受。因为即使是优秀的DOS编程人员,

编写保护模式程序也是相当困难的。
    ② 用保护模式的接口产品 DOS扩展器。
    当采用C++编程时,应用DOS扩展器接口跟直接用保护模式编程差不多同样困
难。所以这种方法也不利于一般编程人员。
    ③ 用覆盖技术。
    假如我们要存放的数据远大于代码,用覆盖技术仍然无法解决。
    因此,应该提出更好的方案来。
    由EMS(Lotus-Intel-Microsoft Expanded Memory Specification)规范提供
的中断调用,可以用扩展内存模拟扩充内存,具有强大的功能,为利用扩展内存
提供了方便;同时,XMS扩展内存规范提供了更直接的调用途径, 不需占用上位
内存。但两种规范使用时仍然要处理许多细节。为此,笔者在开发应用程序的过
程中,建立了一个内存管理类,以相对透明的方式分配扩展内存并存储数据,并
具有以磁盘建立虚存的功能。

二、扩充内存管理类
    扩充内存管理类提供了分配扩充内存、转储数据或建立文件缓冲区的功能。

//EMM( for EMS )结构(供移动内存块用)(操作对象包括常规内存和扩充内存)
struct ywEmsEmb
 {
   long     count;           //以字节计的要移动的区域长度
   char     source_mem_type; //源内存类型 0: 常规内存;  1: 扩充内存
   unsigned source_handle;   //源句柄(若为0,则对应的偏移量是常规内存的
段内偏移*)
   unsigned source_offset;   //源初始偏移(常规内存在段内,扩充内存在逻辑
页内)
   union
     {
        unsigned source_seg;      //源内存块常规内存初始段地址
        unsigned source_page_num; //源内存块扩充内存逻辑页
     };
   char     dest_mem_type;   //目的内存类型 0: 常规内存;  1: 扩充内存

   unsigned dest_handle;     //目的句柄(若为0,则对应的偏移量是常规内存
的段内偏*)
   unsigned dest_offset;     //目的初始偏移(常规内存在段内,扩充内存在逻
辑页内)

   union
     {
        unsigned dest_seg;        //目的内存块常规内存初始段地址
        unsigned dest_page_num;   //目的内存块扩充内存逻辑页
     };
 };

class ywEmsMem                 //扩充内存类
{
 private:
   Boolean init_success;      //析构函数初始化是否成功
   int ems_handle;            //本扩充内存对象句柄
   int ems_pages;             //本句柄所对应的页数
   Boolean error_code;        //最近一次操作的错误代码(含义及定义参考中
断 67H *)
   long useful_size;          //本句柄中的有效数据
   long ems_point;            //分配到的扩充内存块的内部指针;其值为本句
柄所对应
                              //扩充内存块中的偏移量
   char far * ems_page_frame; //映射窗口段地址
 public:
   ywEmsMem(void);                   //产生未经初始化处理的ywEmsMem对象

   ywEmsMem(int  pages);            //产生pages个页面大小的ywEmsMem对象

   ywEmsMem(long * size);


    /*产生*size字节大小的ywEmsMem对象应使size的大小为16K的整数倍
      否则,将分配到大于申请空间的内存,即将size进位16K的整数倍分配*/
   ywEmsMem(char * filename,long * size);
     //产生一个与文件filename相关联的对象,其空间大于或等于文件大小
     //并已把文件中内容读入其中
   ~ywEmsMem();
   Boolean InitEms(void);       //检测是否安装EMS驱动程序及硬件能否正常
工作
   Boolean GetInitResult(void); //取得初始化结果(成功或不成功)
   Boolean  MallocEms(int pages);                   //分配页面
   Boolean  ReMallocEms(Handle handle, int pages);  //重新分配页面
   Boolean  FreeEms(int handle);         //释放句柄所对应的页面
   Boolean  MapEms( int Physical_page, int Logical_page);
                                         //映射页面存储器
   Boolean  MoveEmsMem( const struct ywEmsEmb * emb); //移动内存块; em
b--移动操*

   Boolean  GetErrorCode(void);     //取得最近一次操作的错误代码的内存
结构
   int   GetCurentPages(void);      //取得本句柄所对应内存的大小(以页计
)
   long  GetCurentSize(void);       //取得本句柄所对应内存的大小(以字节
计)
   long  GetUsefulSize(void);        //取得本句柄所有效数据占用的内存的
大小
   Boolean   SetEmsPoint(long Pnt);  //设置当前指针位置
   Boolean   SetEmsPages(int pages); //重新设置本句柄所对应的页数
   Boolean   SetEmsSize(long * size);//重新设置本句柄所对应的字节数
   void  SetEmsDataIvalue(void);     //设置句柄中的所有内容无效并置内部
指针位置
   long  GetEmsPoint(void);          //取得当前指针位置
   Boolean   Ems_CharOnPoint(char far * ch , char mode );
                      //从当前指针处读取(或写入)一个字节
                      //读(写)完数据后,指针自动移动一个字节位置
                      //当 mode = READCHAR时,写入;当mode = WRITECHAR时
,读出
   Boolean  Ems_CharOnOff( long offset, char far * ch , char mode );
                      //从偏移量为offset处读取(或写入)一个字节
                      //读(写)数据时,不影响当前的指针位置
                      //当 mode = READCHAR时,写入;当mode = WRITECHAR时
,读出
   Boolean Buffer_Ems( char far * buffer, long size, char mode );
                      //从当前扩充内存内部指针处读取size大小的数据到缓
冲区
                      //或将缓冲区中size大小的数据写入到当前指针所在位

                      //mode = READCHAR: 读出; WRITECHAR: 写入
   Boolean  WriteEmsToFile(char * filename, char * mode, long size);
                      //将从当前指针位置开始的size字节数据写入文件
   Boolean  ReadFileToEms(char * filename,long * size );
                //将文件filename中的内容读入扩展内存的指针所在处的连续
空间
   Boolean  UsefulEmsToFile(char * filename,char * mode);
                //将本句柄所对应的EMS中的有效数据内容写入文件
   Boolean  AllEmsToFile(char * filename,char * mode);
                //将本句柄所对应的EMS中的所有内容写入文件
};

三、主内存管理类
    主内存管理类提供了同时管理扩充内存和扩展内存( 如其中之一不存在,不
影响系统运行)的功能。另外还具有只占用340字节常规内存就可将任意大小的屏
幕图像保存到扩展内存的功能。限于篇幅,此处略去扩展内存管理部分和保存图
像部分。
    主内存在管理内存的最大特点是当扩充内存和扩展内存都耗尽时,能够自动
将存储后长时间没有使用的数据交换到磁盘上,满足当前分配的要求;当被交换
到硬盘的数据要用到时,又能够自动交换到内存。具体实现方法是:每当分配一
块内存后,主内存管理对象首先将被分配的内存句柄放入队尾;当内存不够时,
从队列的队首取出最早分配的句柄。若该句柄未加锁,就把该句柄所对应的全部
或部分数据交换到硬盘上;若该句柄已加锁,将该句柄号放入队尾,继续判断当
前队首的句柄对应的数据是否可交换,直到找到为止。    在这里还略去了建立
内存堆之后的内存表、存储块等结构。


--
m;31m※ 来源:.网易虚拟社区 http://club.netease.com.[FROM: 202.102.65.183]m
--
m;34m※ 转寄:.网易 BBS bbs.netease.com.[FROM: bbs.huizhou.gd.cn]m
..

--



日出东方,唯我不败;
    天上地下,唯我独尊。

※ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: 192.168.1.143]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店