Database 版 (精华区)
发信人: wodeji (西西), 信区: Database
标 题: [转载] PowerBuilder 开 发 系 列 谈 (13)
发信站: 紫 丁 香 (Tue Sep 29 17:51:43 1998), 站内信件
【 以下文字转载自 Programming 讨论区 】
【 原文由 two 所发表 】
内 存 漏 洞
我 们 在 上 期 的《 预 装 入 对 象》 一 文 中 提 到 了 关 于 内 存 漏
洞(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() 函 数,
您 可 以 确 定 是 否 有 足 够 的 资 源 用 来 继 续 正 常 打 开。 这 些 函 数 也 可 以 在
应 用 的 任 何 地 方 调 用 以 重 置 限 制 或 检 查 资 源。
--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: 202.97.236.132]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: whs.hit.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: cadcam.hit.edu.c]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:211.582毫秒