万卷书>>电脑书籍>>程序设计>>pb程序设计>>PowerBuilder系列讲座

WANJUANSHU.COM

13. 资源管理
  内 存 漏 洞

  我 们 在 上 期的《 预 装 入 对 象》 一 文 中 提 到 了 关 于 内 存 漏 洞(MemoryLeak)的 问 题。 内 存 漏 洞 是 程 序 员 和 用 户 都 很 关 心 的 问 题。一 个 对 象 被 装 入 并 且 分 配 了 内 存, 而 在 对 象 被 关 闭 却没 有 释 放 分 配 的 内 存, 这 时 一 个 内 存 漏 洞 就 产 生 了。在 开 发 工 具 中 也 会 有 内 存 漏 洞, 这 是 我 们 无 法 控 制的, 但 是 我 们 必 须 注 意 我 们 自 己 的 代 码 所 造 成 的 内 存漏 洞。

  最 有 可 能 造成 内 存 漏 洞 的 是 使 用CREATE 语 句 创 建 一 个 对 象 后 没 有 对应 的DESTROY 语 句 消 除。 无 论 何 时, 您 用CREATE 函 数 创 建 了 一个 对 象, 您 就 必 须 负 责 在 该 对 象 执 行 完 成 之 后 释 放 分配 的 内 存。

  例: 我 创 建了 我 自 己 的 一 个transaction 对 象:

  TransactionMy_Transaction

  My_transaction=CREATETransaction

  当 我 用 完 这 个 对 象 后, 我 应 该清 除 该 对 象:

  DESTROYMyTransaction

  ( 注:SQLCA 是 由 您 的 应 用 自 动 创建 同 时 也 自 动 关 闭。)

  内 存 漏 洞 的出 现 经 常 是 与 开 发 者 使 用 了 非 可 视 化 用 户 对 象 有 关。因 为 这 种 对 象 只 能 用CREATE 语 句 创 建 它 的 一 个 实 例, 因此 如 不 对 其 使 用DESTROY 语 句 消 除, 则 必 然 导 致 错 误。 另外 一 个 有 关 的 是 用OpenUserObject 或OpenUserObjectWithParm 函 数 创 建的 动 态 用 户 对 象, 这 些 对 象 同 样 要 求 您 在 结 束 使 用 它们 时 用 相 应 的CloseUserObject 函 数。

  我 们 知 道,PowerBuilder 能 够 自 动 清 除 放 在 一 个 窗 口 中 的 常 规 对 象, 但 它 为 什么 不 能 在 应 用 结 束 时 自 动 清 除 用 户 自 己 创 建 的 对 象呢 ? 因 为PowerBuilder 仅 能 清 除 控 件 列 表 中 的 对 象, 而 且 只有 一 个 对 象( 如 窗 口) 及 其 表 面 的 那 些 对 象 才 会 列 在控 件 列 表 当 中( 包 括 不 可 见 的 对 象)。 而 动 态 的 用 户对 象 和 非 可 视 化 对 象, 与PowerBuilder 全 局 对 象 的 实 例(transactions、error、message 等 等) 一 样, 是 在 对 象 的 控 制 列 表 已 经 创 建 后 加 到 对象 上 的。 关 闭 父 对 象 时, 系 统 并 不 知 道 要 清 除 这 些 动态 加 入 的 对 象。 如 果 您 没 有 手 工 消 除 它 们, 它 们 将 一直 保 持 打 开 状 态, 并 常 驻 在 内 存 中, 直 到 使 用 工 具 来清 除, 或 者 关 闭Windows 系 统。 使 用 象Windows3.1ResourceKit 中 提 供的 内 存 资 源 监 控 器 这 样 的 工 具, 能 使 您 在 测 试 过 程 中检 查 资 源 以 确 定 资 源 按 照 预 想 的 那 样 被 释 放。 内 存 管 理

  在Windows3.x 平 台上, 开 发 人 员 编 译 时 会 遇 到 这 样 的 问 题: 机 器 里 有32M 内 存, 而 且 只 有 两 个 应 用 在 运 行, 可 是PowerBuilder 却 总 是提 示 内 存 不 足(OutofMemory)。 而 用 户 在 使 用 某 应 用 软 件时, 也 会 同 样 出 现 内 存 不 足 的 问 题, 于 是 用 户 只 得 关闭 其 它 的 应 用, 直 到 发 现 关 闭 了 某 一 程 序 释 放 了 足 够的 内 存 空 间 可 供PowerBuilder 运 行 起 来 为 止。 于 是 用 户 开 始抱 怨 开 发 者, 而 开 发 者 开 始 抱 怨PowerBuilder。

  其 实 在 多 数情 况 下, 他 们 都 不 应 该 受 责 备, 问 题 的 根 源 出 在Windows 本 身。 我 们 知 道, 从 严 格 意 义 上 讲,Windows 并 不 是 一 个操 作 系 统, 它 只 是 一 个DOS 应 用 程 序, 它 仍 然 要 求 固 定的 程 序 空 间。 这 些 空 间 分 布 在1M 以 下 的 上 位 内 存 中。如 果 您 使 用 带 参 数/C 的DOS 命 令MEM, 您 将 会 看 到 类 似 以 下的 显 示。

Modulesusingmemorybelow1MB:

Name	Total	=Conventional	+UpperMemory
--------	----------	---------	--------
MSDOS	17,533(17K)	17,533(17K)	0(0K)
HIMEM	1,120(1K)	1,120(1K)	0(0K)
EMM386	4,144(4K)	4,144(4K)	0(0K)
POWER	80(0K)	80(0K)	0(0K)
COMMAND	3,888(4K)	3,888(4K)	0(0K)
win386	44,816(44K)	2,384(2K)	42,432(41K)
NAVTSR	7,984(8K)	7,984(8K)	0(0K)
MOUSE	25,328(25K)	272(0K)	25,056(24K)
SHARE	26,368(26K)	26,368(26K)	0(0K)
DOSKEY	4,144(4K)	4,144(4K)	0(0K)
WIN	1,760(2K)	1,760(2K)	0(0K)
COMMAND	4,048(4K)	4,048(4K)	0(0K)
POWER	4,672(5K)	0(0K)	4,672(5K)
SMARTDRV	29,024(28K)	0(0K)	29,024(28K)
Free	581,312(568K)	581,312(568K)	0(0K)

MemorySummary:

TypeofMemory	Total	=Used	+Free
-----------	----------	----------	----------
Conventional	655,360	74,048	581,312
Upper	101,184	101,184	0
Reserved	393,216	393,216	0
Extended(XMS)	19,821,760	18,773,184	1,048,576
----------	----------	----------	----------
Totalmemory	20,971,520	19,341,632	1,629,888
Totalunder1MB	756,544	175,232	581,312

Largestexecutableprogramsize581,296(568K)
Largestfreeuppermemoryblock0(0K)
MS-DOSisresidentinthehighmemoryarea.




  尽 管 在DOS 内存 限 制640K 和1M 上 位 内 存 块 之 间 有360K( 约384,000 字 节) 的 可用 内 存, 但 在 显 示 中,“ 上 位” 内 存 和“ 保 留” 内 存 之间 却 有 近500K 可 用。“ 保 留” 内 存 一 般 用 来 装 载 网 络 软件 和 其 它 的 驱 动, 在"Win386" 一 行 也 显 示 还 有42K 可用, 这 是 被 那 些 需 要 固 定 地 址 空 间 的 应 用 使 用 的。 当Windows 创 建 一 项 新 任 务 时,Windows 的 装 入 模 块 为 该 任 务 创 建 一个 任 务 数 据 库(TDB)。 这 个 任 务 数 据 库 必 须 被 装 入 到1MB 以下 内 存, 而 且 最 小 长 度 为200 字 节。 原 因 是 任 务 数 据 库项 的 第 二 部 分 是 一 个 程 序 段 前 缀(PSP), 这 是Windows1.0、2.0 和3.0 实 模 式 创 造 的, 使 用 它 的 唯 一 原 因 是 更 加 容 易 地调 度 应 用 内 置 的MS-DOS 扩 展 器。 在 保 护 模 式 的Windows 并 不是 必 需 的, 不 过 在Windows3.1 保 护 模 式 中 仍 保 留 了 这 一 结构。

  无 论 您 的 机器 是 多 少 兆 内 存, 您 的 程 序 必 须 去 争 取 这 段 可 用 空间, 没 有 什 么 方 法 可 以 扩 充 它。 这 一 限 制, 以 及 下 面将 提 到 的64KGDI 和USER 堆, 是Windows3.X 中 最 受 限 制 的 代 码。

  所 有 的Windows 程 序 或 多 或 少 需 要 一 些 这 种1M 以 下 的 内 存 才 能 正 常 工作。 一 般 的 程 序 除 分 配 了 一 些 固 定 的 内 存 外, 有 些 程序 还 要 另 外 申 请 一 些 内 存 空 间, 而 有 些 有 错 误 的 程 序会 很 快 地 消 耗 掉 这 段 有 限 的 内 存 空 间, 这 就 会 出 现 前面 我 们 所 提 到 的 内 存 不 足 问 题。 不 过PowerBuilder 并 不 让 我们 自 己 去 分 配 这 些 稀 有 的 资 源, 这 也 使 我 们 无 法 解 决这 种 原 因 引 起 的 内 存 不 足 问 题。

  C 程 序 员 会 很熟 悉 用GMEM_FIXED 或 是 用GlobalDosAlloc 函 数 分 配 内 存。 这 两 个 函数 都 将 试 图 分 配 低 于1M 的 内 存。HEAPWALK.EXE( 包 含 在WindowsSDK 或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.;

  创 建 一 个 用于 声 明 的 应 用 事 件, 并 从CONSTRUCTOR 事 件 中 触 发 该 事 件。

  创 建 一 个 用于 初 始 化 的 用 户 事 件NVO_UE_SETUP, 并 从CONSTRUSTOR 中 触 发。

  步 骤 二:

  声 明 以 下 的局 部 外 部 函 数:

  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,sdkResources=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(sdkResources) < il_memory_limit then return(sdkMemory*-1) end if Return1




  步 骤 五:

  我 们 需 要 创 建 一 个 函 数 用 于 建立 我 们 的 最 小 资 源 限 制。 创 建 函 数NVOF_Set_Resource_Limit。 输入 参 数 是 整 型 变 量ai_ResourceType, 它 指 代 可 用 资 源 常 量 种类(GDI,User 或 Memory) 和ai_threshhold, 指 代 这 种 资 源 类 型 的 临 界限 制 值。


//***********************************************
//	 函 数:	NVOF_Set_Resource_Limit
//	 作 用:	Set 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 sdkSystem
		il_Memory_Limit=ai_Threshhold
End Choose
Return1




  步 骤 六:

  在 声 明 事 件 中, 将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() 函 数, 您 可 以 确 定 是 否 有 足 够 的 资 源 用 来 继 续 正 常 打开。 这 些 函 数 也 可 以 在 应 用 的 任 何 地 方 调 用 以 重 置 限制 或 检 查 资 源。
上一页 WanJuanShu.COM 下一页
WANJUANSHU.COM 万卷书