Database 版 (精华区)
发信人: lizhenguo (夸父·追日), 信区: Database
标 题: 13
发信站: 哈工大紫丁香 (2001年09月26日18:42:50 星期三), 站内信件
bbs.hit.edu.cn
PowerBuilder专栏
[回到开始][上一层][下一篇]
----------------------------------------------------------------------------
----
发信人: carsam (独自偷...), 信区: Database
标 题: PowerBuilder应用开发系列讲座(13)
发信站: 逸仙时空 Yat-sen Channel (Wed Jan 5 11:37:19 2000), 站内信件
PowerBuilder应用开发系列讲座(13)
----------------------------------------------------------------------------
----
资源管理
内存漏洞
我们在上期的《预装入对象》一文中提到了"内存漏洞(Memory Leak)",这是程序员和用
户都很关心的问题。一个对象被装入并且分配了内存,而在对象被关闭时却没有释放分配
的内存,这样,内存漏洞就产生了。在开发工具中也会有内存漏洞,这是我们无法控制的,
但是我们必须注意我们自己的代码所造成的内存漏洞。
最有可能造成内存漏洞的是,使用CREATE语句创建一个对象后没有用对应的DESTROY语句
消除。无论何时,用CREATE函数创建了一个对象,就必须负责在该对象执行完成之后释放
分配的内存。
例:创建一个transaction对象:
Transaction My_Transaction
My_transaction=CREATE Transaction
当用完这个对象后,应该清除该对象:
DESTROY-My-Transaction
(注意:SQLCA由应用自动创建,同时也自动关闭。)
内存漏洞的出现经常是与开发者使用了非可视化用户对象有关。因为这种对象只能用CR
EATE语句创建它的一个实例,因此如不对其使用DESTROY语句消除,则必然导致错误。另外
用OpenUserObject或OpenUser-ObjectWithParm函数创建的动态用户对象,同样要求开发
者在结束使用它们时调用相应的CloseUserObject函数。
我们知道,PowerBuilder能够自动清除放在一个窗口中的常规对象,但它为什么不能在应
用结束时自动清除用户自己创建的对象呢?因为PowerBuilder仅能清除控件列表中的对象
,而且只有一个对象(如窗口)及其表面的那些对象才会列在控件列表当中(包括不可见的
对象);而动态的用户对象和非可视化对象,与PowerBuilder全局对象的实例(transactio
ns、error、message等等)一样,是在对象的控制列表已经创建后加到对象上的。关闭父
对象时,系统并不知道要清除这些动态加入的对象。如果开发者没有手工消除它们,它们
将一直保持打开状态,并常驻在内存中,直到使用工具来清除,或者关闭Windows系统。使
用像Windows3.1 Resource Kit中提供的内存资源监控器那样的工具,能使您在测试过程
中检查资源以确定资源按照预想的那样被释放。
内存管理
在Windows3.x平台上,开发人员编译时会遇到这样的问题:机器里有32M内存,而且只有两
个应用在运行,可是PowerBuilder却总是提示内存不足(Out of Memory)。而用户在使用
某应用软件时,也会同样出现内存不足的问题,于是用户只得关闭其它的应用,直到发现关
闭了某一程序释放了足够的内存空间可供PowerBuilder运行为止。于是用户开始抱怨开
发者,而开发者开始抱怨PowerBuilder。
其实在多数情况下,他们都不应该受责备,问题的根源出在Windows本身。我们知道,从严
格意义上讲,Windows并不是一个操作系统,它只是一个DOS应用程序,它仍然要求固定的程
序空间。这些空间分布在1M以下的上位内存中。如果您使用带参数/C的DOS命令MEM,您将
会看到类似以下的显示(见右下表)。
尽管在DOS内存限制640K和1M上位内存块之间有360K(约384,000字节)的可用内存,但在显
示中,"上位"内存和"保留"内存之间却有近500K可用。"保留"内存一般用来装载网络软件
和其它的驱动,在"Win386"一行也显示还有42K可用,这是被那些需要固定地址空间的应用
使用的。当Windows创建一项新任务时,Windows的装入模块为该任务创建一个任务数据库
(TDB)。这个任务数据库必须被装入到1MB以下内存,而且最小长度为200字节。原因是任
务数据库项的第二部分是一个程序段前缀(PSP),这是Windows1.0、2.0和3.0实模式创造
的,使用它的唯一原因是更加容易地调度应用内置的MS-DOS扩展器。在保护模式的Win-d
ows中并不是必需的,不过在Windows3.1保护模式中仍保留了这一结构。
无论您的机器有多少内存,您的程序必须去争取这段可用空间,没有什么方法可以扩充它
。这一限制,以及下面将提到的64K GDI和USER堆,是Windows3.X中最受限制的代码。
所有的Windows程序或多或少需要一些这种1M以下的内存才能正常工作。一般的程序除分
配了一些固定的内存外,有些程序还要另外申请一些内存空间,而有些有错误的程序会很
快地消耗掉这段有限的内存空间,这就会出现前面我们所提到的内存不足问题。不过Pow
erBuilder并不让我们自己去分配这些稀有的资源,这也使我们无法解决这种原因引起的
内存不足问题。
C程序员会很熟悉用GMEM_FIXED或是用Global-DosAlloc函数分配内存。这两个函数都将
试图分配低于1M的内存。HEAPWALK.EXE(包含在Windows SDK或C++编译器中)这样的应用
程序能查看1M以下分配的内存块,从而更准确地确定哪些应用吃掉了宝贵的内存资源。可
以用MS-DOS中的LoadHigh功能,将一些驻留程序装入高端而释放常规内存,但这样做也减
少了可用的上位内存,最好办法只能是折衷。
其它Windows资源
还有两种Windows中常常引起问题的资源,它们是USER和GDI资源。这些资源就像上面描述
的任务数据库区一样,也是被Windows而不是被机器内存限制的,它们都有不能超过64K的
限制。这意味着有时并不是机器内存总数引起了内存不足。
GDI资源就是应用中用到的资源句柄和设备上下文。每个位图、图标、光标、数据窗口、
用户对象和窗口都需要这种资源。大的自定义工具条对GDI资源的需求最大,但它一般不
会引起麻烦。窗口、数据窗口和按钮将最终用光GDI资源。GDI资源几乎无一例外地最先
减少到20%以下。
USER资源也是每个对象都需要的资源。如果一个用户对象由一组对象组成,其中每个对象
都需要USER资源(句柄、任务管理等等),这种情况下调用动态打开或关闭的对象显然是有
益的。因为数据窗口是单一对象,所以使用数据窗口作为对象集合也是给这些资源减少负
担的一个好方法。
通过上述介绍,我们可以看到Windows3.x中可用的内存远比您最开始想象的要少。Windo
ws95也许将会缓解这一问题,但仍需观察。
动态监控资源例程
最后,我们介绍一个能帮您在运行时跟踪您的系统资源的例程。我们曾提到过,使用Powe
rBuilder,我们不能控制系统对资源的使用,但是我们可以用一些简单的SDK函数调用来监
控资源的使用。我们将使用一个非可视化对象作为SDK的界面对象。当然您也可以将SDK
函数声明为全局外部函数并通过全局函数来访问它们。
步骤一:
创建API访问对象NVO_API_ACCESS;
创建一个用于声明的应用事件,并从CONSTRUC-TOR事件中触发该事件;
创建一个用于初始化的用户事件NVO_UE_SETUP,并从CONSTRUCTOR中触发。
步骤二:
步骤二:
声明以下的局部外部函数:
FUNCTION uint GetFreeSystemResources(uint SysResource) LIBRARY 'user.dll'
步骤三:
声明以下变量实例:
Private:
/*最小的资源限制*/
Long il_usermem_limit
Long il_gdimem_limit
Long il_memory_limit
Long il_standard_threshhold
/*资源访问常量*/
Integer sdkUser=0,sdkGDI=1,sdkMemory=2
步骤四:
创建以下的用户对象函数:
//**************************
// 函数: NVOF_Check_Resources
// 功能: To check system resources
// 参数:(无)
// 返回值:integer
// 1-成功,<0-失败(绝对数值为资源访问常量)。
//*************************
if GetFreeSystemResources(sdkUser) < il_usermem_limit then
return(sdkUser*-1)
end if
if GetFreeSystemResources(sdkGDI) < il_gdimem_limit then
return(sdkGDI*-1)
end if
if GetFreeSystemResources(sdkMemory) < il_memory_limit then
return(sdkMemory*-1)
end if
Return 1
步骤五:
我们需要创建一个函数用于建立我们的最小资源限制。
创建函数NVOF_Set_Resource_Limit。输入参数是整型变量ai_ResourceType,它指代可用
资源常量的种类(GDI,User或 Memory)和ai_threshhold,指代这种资源类型的临界限制值
。
//**************
// 函数: NVOF_Set_Resource_Limit
// 作用: Sets resource threshhold limits
// 参数: integer ai_ResourceType
// (指代可用资源常量种类)
// integer ai_Threshhold
// (这种资源类型的临界限制值)
// 返回值:integer
// 1-成功,-1-失败.
//
//*****************
/*设置资源极限*/
Choose Case ai_ResourceType
Case sdkGDI
il_gdimem_limit=ai_Threshhold
Case sdkUser
il_usermem_limit=ai_Threshhold
Case sdkMemory
il_memory_limit=ai_Threshhold
End Choose
Return 1
步骤六:
在声明事件中,将il_Default_Threshold设为稍大一些的数值。例如,30%可能是您能接受
的最低的不用警告用户的资源量,那么我们在声明事件中写下如下代码:
il_Default_Threshold=30
在初始化事件中,建立缺省函数以设定临界限制,函数可以在运行时重置这些限制。开发
过程中将限制设得高一点,这样确保在最后产品运行时资源不会出问题。
NVOF_Set_Resource_Limit(sdkUser,il_Default_Threshold)
NVOF_Set_Resource_Limit(sdkGDI,il_Default_Threshold)
NVOF_Set_Resource_Limit(sdkMemory,il_Default_Threshold)
小结
建立上述对象的一个实例,在打开一个窗口、动态打开一个用户对象或创建一个对象之前
,通过调用对象的NVOF_Check_Resources()函数,您可以确定是否有足够的资源用来继续
正常打开。这些函数也可以在应用的任何地方调用以重置限制或检查资源。
--
我想自由自在地飞......
飞过大海...
飞过沙漠...
飞翔在星的夜空......
※ 来源:.逸仙时空 Yat-sen Channel bbs.zsu.edu.cn.[FROM: 202.116.90.29]
----------------------------------------------------------------------------
----
[回到开始][上一层][下一篇]
欢迎访问Cterm主页
--
《列子·汤问》:“夸父不量力,欲追日影,逐之于隅谷之际。渴欲 得饮,赴饮河渭
。河渭不足,将走北饮大泽。未至,道渴而死。”
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.229.154]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.490毫秒