pb 在 dw 中的内存漏洞问题

billxia 2002-09-16 08:50:13
dbs 是一个 datastore

dbs.modify("DataWindow.print.orientation="+string(lorientation)) dbs.modify("DataWindow.print.paper.size="+string(lsize))
dbs.modify("DataWindow.print.DocumentName='"+lDocumentName+"'")
dbs.modify("DataWindow.print.Margin.Left="+string(lLeft))
dbs.modify("DataWindow.print.Margin.right="+string(lright))
dbs.modify("DataWindow.print.Margin.top= "+string(ltop))
dbs.modify("DataWindow.print.Margin.bottom="+string( lbottom))
上述语句执行后,dbs 对象不能完全释放,还有300k 内存被占用

请问有什么方法可以完全释放这个对象?


...全文
144 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
superneo 2002-09-30
  • 打赏
  • 举报
回复
up
dmm 2002-09-26
  • 打赏
  • 举报
回复
market,,
ice2water 2002-09-26
  • 打赏
  • 举报
回复
up
vactorwj 2002-09-25
  • 打赏
  • 举报
回复
去pb.blueexpress.com.cn问问吧。
balloonman2002 2002-09-25
  • 打赏
  • 举报
回复
第十三讲:资源管理

张健姿
01-6-22 下午 03:18:07

--------------------------------------------------------------------------------


内存漏洞
我们在上期的《预装入对象》一文中提到了"内存漏洞(Memory Leak)",这是程序员和用户都很关心的问题。一个对象被装入并且分配了内存,而在对象被关闭时却没有释放分配的内存,这样,内存漏洞就产生了。在开发工具中也会有内存漏洞,这是我们无法控制的,但是我们必须注意我们自己的代码所造成的内存漏洞。
最有可能造成内存漏洞的是,使用CREATE语句创建一个对象后没有用对应的DESTROY语句消除。无论何时,用CREATE函数创建了一个对象,就必须负责在该对象执行完成之后释放分配的内存。
例:创建一个transaction对象:
Transaction My_Transaction
My_transaction=CREATE Transaction
当用完这个对象后,应该清除该对象:
DESTROY-My-Transaction
(注意:SQLCA由应用自动创建,同时也自动关闭。)
内存漏洞的出现经常是与开发者使用了非可视化用户对象有关。因为这种对象只能用CREATE语句创建它的一个实例,因此如不对其使用DESTROY语句消除,则必然导致错误。另外用OpenUserObject或OpenUser-ObjectWithParm函数创建的动态用户对象,同样要求开发者在结束使用它们时调用相应的CloseUserObject函数。
我们知道,PowerBuilder能够自动清除放在一个窗口中的常规对象,但它为什么不能在应用结束时自动清除用户自己创建的对象呢?因为PowerBuilder仅能清除控件列表中的对象,而且只有一个对象(如窗口)及其表面的那些对象才会列在控件列表当中(包括不可见的对象);而动态的用户对象和非可视化对象,与PowerBuilder全局对象的实例(transactions、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-dows中并不是必需的,不过在Windows3.1保护模式中仍保留了这一结构。
无论您的机器有多少内存,您的程序必须去争取这段可用空间,没有什么方法可以扩充它。这一限制,以及下面将提到的64K GDI和USER堆,是Windows3.X中最受限制的代码。
所有的Windows程序或多或少需要一些这种1M以下的内存才能正常工作。一般的程序除分配了一些固定的内存外,有些程序还要另外申请一些内存空间,而有些有错误的程序会很快地消耗掉这段有限的内存空间,这就会出现前面我们所提到的内存不足问题。不过PowerBuilder并不让我们自己去分配这些稀有的资源,这也使我们无法解决这种原因引起的内存不足问题。
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中可用的内存远比您最开始想象的要少。Windows95也许将会缓解这一问题,但仍需观察。
动态监控资源例程
最后,我们介绍一个能帮您在运行时跟踪您的系统资源的例程。我们曾提到过,使用PowerBuilder,我们不能控制系统对资源的使用,但是我们可以用一些简单的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()函数,您可以确定是否有足够的资源用来继续正常打开。这些函数也可以在应用的任何地方调用以重置限制或检查资源。
hongqi162 2002-09-24
  • 打赏
  • 举报
回复
关注!
bravebarbarian 2002-09-22
  • 打赏
  • 举报
回复
我是这样想的.你既然要用n回,你就最后一次释放该对象
dashuh 2002-09-22
  • 打赏
  • 举报
回复
这的确存在我还经常碰到内存冲突这种提示!
warchild 2002-09-19
  • 打赏
  • 举报
回复
不易下这么快的定论,硬件环境
killerdanny 2002-09-19
  • 打赏
  • 举报
回复
新来不是有个SYBASE技术人员开的论坛,你去那问问他们吧!呵呵!










killerdanny 2002-09-19
  • 打赏
  • 举报
回复
新来不是有个SYBASE技术人员开的论坛,你去那问问他们吧!呵呵!










billxia 2002-09-19
  • 打赏
  • 举报
回复
发现问题之一是:在 pb 8.02 中的函数里面的 子数据窗口 不能自动释放内存在函数结束的时候,必须放到对象中(如窗口,自定义数据对象中)才行. 300k 数据的得到是因为执行了50次一共丢失了1.5M 内存,使用的根据很多(如系统自己的检测程序或者使用api函数得到内存数据),现在还有100k,不知道丢失的理由
咖啡 2002-09-18
  • 打赏
  • 举报
回复
呵呵,这么做看行不行:
dbs.DataObject = ''

Destroy(dbs)
balloonman2002 2002-09-18
  • 打赏
  • 举报
回复
DEBUG进去,看看还有什么东东 ,:)
我也想知道老兄是怎么知道300K这个数字的?
这300K你断定是DW造成的吗?
佣工7001 2002-09-18
  • 打赏
  • 举报
回复
Datawindow同样有这问题,我已经忍了多年了!
heliang 2002-09-18
  • 打赏
  • 举报
回复
300k 内存被占用?

老兄,你是怎么测到这些数据的?

flyhot 2002-09-18
  • 打赏
  • 举报
回复
retrieve()看看怎么样?
xingxing 2002-09-18
  • 打赏
  • 举报
回复
destroy dbs
are2000 2002-09-17
  • 打赏
  • 举报
回复
那你改用datawindow试试
jzhaohua 2002-09-16
  • 打赏
  • 举报
回复
create 出来的一般都要 destroy 以释放资源
即使是弹出式菜单, 如果是 create 出来的, 最好也 destroy
加载更多回复(5)

1,075

社区成员

发帖
与我相关
我的任务
社区描述
PowerBuilder 相关问题讨论
社区管理员
  • 基础类社区
  • WorldMobile
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧