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毫秒