首页> 中国专利> 一种组件对象模型对象的监控方法和装置

一种组件对象模型对象的监控方法和装置

摘要

本发明实施方式提出了一种组件对象模型(COM)对象的监控方法和装置。包括:为待监控COM对象的虚函数创建拦截函数;通过所述拦截函数调用所述虚函数,并将在该调用过程中的所述待监控COM对象的引用计数操作记录及所述引用计数操作对应的调用栈信息保存到所述COM对象跟踪表中。本发明实施方式实现了对COM对象的跟踪,可以对COM对象资源利用进行有效监控,并优化系统资源,而且可以定位系统运行过程中产生的无法销毁的COM对象,并追查原因,进而解决COM对象引用计数失衡引发的一系列系统问题。

著录项

  • 公开/公告号CN103309796A

    专利类型发明专利

  • 公开/公告日2013-09-18

    原文格式PDF

  • 申请/专利权人 腾讯科技(深圳)有限公司;

    申请/专利号CN201210061013.0

  • 发明设计人 常青;

    申请日2012-03-09

  • 分类号G06F11/36;G06F9/46;

  • 代理机构北京德琦知识产权代理有限公司;

  • 代理人谢安昆

  • 地址 518044 广东省深圳市福田区振兴路赛格科技园2栋东403室

  • 入库时间 2024-02-19 20:43:39

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2016-06-15

    授权

    授权

  • 2014-11-05

    实质审查的生效 IPC(主分类):G06F11/36 申请日:20120309

    实质审查的生效

  • 2013-09-18

    公开

    公开

说明书

技术领域

本发明实施方式涉及计算机技术领域,更具体地,涉及一种组件对象模 型(Component Object Model,COM)对象的监控方法和装置。

背景技术

COM技术是微软于1993年提出的一种用于软件开发的二进制组件技 术,意在解决编程语言的互通问题。在COM构架下,人们可以开发出各种 各样功能专一的组件,然后将它们按照需要组合起来,构成复杂的应用系统。 由此带来的好处是多方面的:可以将系统中的组件用新的替换掉,以便随时 进行系统升级和定制;可以在多个应用系统中重复利用同一个组件;可以方 便地将应用系统扩展到网络环境下;COM与语言,平台无关的特性使所有 的程序员均可充分发挥自己的才智与专长编写组件模块;等等。

COM对象是遵循COM规范的COM类所创建出的对象,如果以C++ 实现的COM对象为例,其与普通对象的区别在于虚表结构等遵循微软的 COM规范。

目前有很多针对应用程序的资源监控工具,可以跟踪应用程序从某个时 间点开始后的资源占用情况,目前主要监控两类资源:内存和图形设备接口 (GDI)。对内存的操作不当,比如申请后却没有释放,就会造成内存泄漏, 使应用程序所占用的内存越来越大,直至崩溃。而对于GDI对象,如果申 请后却没有释放,也会导致GDI泄漏,使应用程序的GDI资源被耗尽。

然而,资源“泄漏”并不仅限于内存和GDI对象,基于COM组件技术 的应用程序也会面临“泄漏”的问题。COM对象本身会占用内存等计算资 源,而COM对象采用“引用计数”来控制其自身的生命期。“引用计数” 是一个大于或等于0的数字,它记录持有该COM对象引用的使用者的数量, 只有当引用计数为0时,COM对象才认为自己已经没有存在的价值,会销 毁自己。所以,如果存在使用者没有释放COM对象的引用,那么该对象将 无法销毁并持续把持占用系统资源,从而导致资源泄露。

可见,在基于COM的系统中,虽然COM对象创建有统一的几个入口 点,但是释放COM对象却没有统一的“释放点”,每个COM对象都是自 己管理自己的死亡,自己释放自己。对系统中的所有COM对象的跟踪需要 能够跟踪所有的创建和释放点,因此现有技术中无法对COM对象的资源利 用进行有效监控,从而显著影响了系统资源优化。

发明内容

本发明实施方式提出一种COM对象的监控方法,以对COM对象的资 源利用进行监控。

本发明实施方式还提出了一种COM对象的监控装置,以对COM对象 的资源利用进行监控。

本发明实施方式的具体方案如下:

一种组件对象模型COM对象的监控方法,该方法包括:

为待监控COM对象的虚函数创建拦截函数;

通过所述拦截函数调用所述虚函数,并将在该调用过程中的所述待监控 COM对象的引用计数操作记录及所述引用计数操作对应的调用栈信息保存 到所述COM对象跟踪表中。

一种COM对象的监控装置,该装置包括拦截函数创建模块和监控模块, 其中:

拦截函数创建模块,用于为待监控COM对象的虚函数创建拦截函数;

监控模块,用于通过所述拦截函数调用所述虚函数,并将在该调用过程 中的所述待监控COM对象的引用计数操作记录及所述引用计数操作对应的 调用栈信息保存到所述COM对象跟踪表中。

从上述技术方案可以看出,在本发明实施方式中,为待监控COM对象 的虚函数创建拦截函数,而且通过所述拦截函数调用所述虚函数,并将在该调 用过程中的所述待监控COM对象的引用计数操作记录及所述引用计数操作对 应的调用栈信息保存到所述COM对象跟踪表中。由此可见,通过跟踪每个 COM对象的“引用计数”变化情况,将应用程序中影响COM对象生命期 的逻辑点在代码级别记录下来,可以定位运行过程中产生的无法销毁的 COM对象,并追查原因,进而解决COM对象引用计数失衡引发的一系列 系统问题,因此实现了对COM对象的有效跟踪,并可以优化系统资源。

附图说明

图1为根据本发明实施方式的COM对象的监控方法流程图;

图2为根据本发明实施方式的基于COM对象跟踪表的监控原理示意 图;

图3为根据本发明实施方式的虚函数拦截示意图;

图4为根据本发明实施方式为生成Hook_AddRef(...)和Hook_Release (...)而创建的可执行代码段示意图;

图5为根据本发明实施方式的COM对象的监控装置结构图。

具体实施方式

为使本发明的目的、技术方案和优点更加清楚,下面结合附图对本发明 作进一步的详细描述。

如前所述,由于COM对象的销毁是自发的,即当一个COM对象发现 自己引用计数为0时,会通过delete this的方式销毁自己,而没有一个统一 的全局释放点来监控所有COM对象,所以不能像对内存和GDI资源的跟踪 一样,简单地通过拦截几个全局释放函数就可以做到。

在本发明实施方式中,通过跟踪COM对象的创建和销毁,找出那些没 有正常释放的COM对象。可以在COM对象创建时将COM对象添加到对 象跟踪表中,在COM对象销毁时将其从表中移除,最后遗留在跟踪表中的 就是泄漏的COM对象。

在本发明实施方式中,通过跟踪每一个COM对象的“引用计数”变化 情况,将应用程序中影响COM对象生命期的逻辑点在代码级别记录下来, 从而实现对COM对象的跟踪。

图1为根据本发明实施方式的COM对象的监控方法流程图。

如图1所示,该方法包括:

步骤101:为待监控COM对象的虚函数创建拦截函数;

在这里,优选分别为待监控COM对象的虚函数AddRef和Release创建 拦截函数。

实际上,还可以选择为待监控COM对象的其它虚函数创建拦截函数, 从而达到COM对象监控的目的,本发明实施方式对此并无限定。

步骤102:通过拦截函数调用虚函数,并将在该调用过程中的待监控 COM对象的引用计数操作记录及引用计数操作对应的调用栈信息保存到所 述COM对象跟踪表中。

下面以选择为虚函数AddRef和Release创建拦截函数为例对步骤102 进行更详细描述。本领域技术人员可以意识到,选择为虚函数AddRef和 Release创建拦截函数仅仅是示范性地,而并不用于限定本发明实施方式的 保护范围。

创建拦截函数,并将拦截函数与虚函数绑定,具体可以将待监控COM 对象的虚函数AddRef的拦截函数伪装为stdcall函数,并将待监控COM对 象的虚函数Release的拦截函数伪装为stdcall函数。同时,在待监控COM 对象的虚函数AddRef的拦截函数中保存虚函数AddRef的地址,并在待监 控COM对象的虚函数Release的拦截函数中保存虚函数Release的地址。

拦截函数对虚函数的调用过程:虚函数AddRef的拦截函数调用该虚函 数AddRef,并将在该调用过程中的引用计数加1操作记录以及与引用计数 加1相关的调用栈信息保存到COM对象跟踪表中;虚函数Release的拦截 函数调用该虚函数Release,并当该COM对象的引用计数不为零时,将在该 调用过程中的引用计数减1操作记录以及与引用计数减1相关的调用栈信息 保存到COM对象跟踪表中,当该COM对象的引用计数为零时,将该待监 控COM对象从COM对象跟踪表中删除。

在一个实施方式中,在为待监控COM对象的虚函数创建拦截函数之前, 还包括创建COM对象跟踪表的步骤。

基于上述流程,下面对本发明实施方式进行更加详细的说明。

首先,对象跟踪表是本发明实施方式创建的数据模块,用来记录当前应 用程序从某一个时间开始所有的COM对象(已经由程序创建但并未销毁)。 一旦启用对象跟踪,对象跟踪表中的数据就会随着应用程序的运行而变化。 优选地,COM对象跟踪表包括:指向待监控COM对象的内存地址的对象 指针、引用计数加1操作记录及与引用计数加1相关的调用栈信息、引用计 数减1操作记录及与引用计数减1相关的调用栈信息。

通常地,每一个被加入该表的COM对象都包含两个重要信息:一个是 对象指针(IUnknown*类型),另一个是该对象被创建时和“引用计数”(即 COM对象的生命期)发生变化时的操作记录以及线程调用栈信息。该操作 记录用于记录该COM对象生命期变化的详细情况,线程调用栈信息则用于 帮助软件开发者在代码级别定位到对象的操作信息。

表1为本发明实施方式一个典型的COM对象跟踪表,它由对象指针和 操作记录等信息组成。

表1

如表1所示,该COM对象跟踪表至少记录了三个对象指针,分别为 obj_pointer_1*、obj_pointer_2*和obj_pointer_3*。而且针对每个对象指针, 都分别记录了其相应的AddRef操作和Release操作,以及在AddRef操作和 Release操作中的相关调用栈栈帧地址表。对于AddRef操作,即为对该COM 对象的“引用计数”增加1;对于Release操作,即为对该COM对象的“引 用计数”减少1,如果该COM对象发现自己的引用计数变为0,则销毁自 己,释放资源,并从上述的跟踪表中移除,以免其影响分析结果。

图2为根据本发明实施方式的基于COM对象跟踪表的监控原理示意 图。当应用程序中新创建了一个COM对象,就应该将其连同调用栈等辅助 开发人员定位问题的信息添加到对象跟踪表中,这样就可以监控到应用程序 从某一时刻起所创建的所有的COM对象。对于遵循COM规范的应用系统 而言,每个进程内的COM对象服务器(一般是DLL组件)都会有 DllGetClassObject导出函数用于统一完成对COM对象的创建,所以需要修 改或拦截DllGetClassObject导出函数,并在对象创建完成后将其加入跟踪表 中。对于另外一些内部创建的COM对象,则需要根据实际情况将COM对 象添加到跟踪表中。

类似地,当一个已经被记录到跟踪表中的COM销毁时,就应该将其从 跟踪表中删除,否则无法判断哪些是正常使用的COM对象,哪些是因为没 有正常释放而产生泄漏的。

当监控停止后,留在跟踪表中的那些COM对象,就属于创建后未被正 常释放的,此时可以根据跟踪表中记录的对象指针和调用栈信息进行逐个分 析。其中在正常情况下,应用程序中缓存COM对象以避免重复创建开销的 情况也很多,所以在分析时要考虑去排除这种情况。

在众多的软件开发过程中,导致COM对象发生泄漏的情况很多,一种 典型的情况是发生了“双向引用”,即两个COM对象相对持有对方的一个 引用,导致双方均无法正常释放。另外的情况是COM对象的使用方操作不 当,遗漏了释放对象引用的逻辑。

由于本发明实施方式拦截两个影响COM对象生命期变化的关键函数, 并对这些操作进行记录,所以可以方便地利用泄漏对象的生命期变化记录找 到泄漏发生的原因。

下面将对这个过程进行更加详细的描述:

由于COM对象“引用计数”的变化并没有公共的入口,每个COM对 象都有自己的处理方式,但是COM规范在内存模型上对COM对象的关键 操作进行了函数级别的严格要求。

从内存模型的角度考虑,每一个遵循COM规范的COM对象在虚函数 表结构上都有相同的地方,即前三个虚函数有相同的顺序,每一个函数也有 相同的声明。

表2展示了一个简单的示范性COM对象的虚函数表结构,前三个虚函 数分别是:

表2

其中与COM对象的生命期密切相关的是第二个虚函数AddRef(...)和 第三个虚函数Release(...)。任何对一个COM对象生命期造成影响的操作 都会调用这两个函数中的一个。

在一个实施方式中,可以通过采用修改虚函数表的方式实现对AddRef (...)和Release(...)的监控。

图3为根据本发明实施方式的虚函数拦截示意图。通过修改虚函数表的 方式实现对AddRef(...)和Release(...)具体可以包括:

首先,为每一个待监控的COM对象创建两个新的拦截函数,假设分别 命名为Hook_AddRef(...)和Hook_Release(...),其中Hook_AddRef(...) 是AddRef(...)的拦截函数,Hook_Release(...)是Release(...)的拦截 函数。

然后,修改待监控的COM对象的虚函数表,将两个旧函数(即AddRef (...)和Release(...))的地址记录下来,并用两个新函数的地址改写旧 地址。

再有,Hook_AddRef(...)要做的工作较为简单,先调用旧的AddRef (...)函数,然后再将相应的AddRef操作记录和堆栈信息记录到跟踪表中。 对于Hook_Release(...)函数,在调用旧的Release(...)函数之后要检查 “引用计数“是否为0,如果不为0,则简单将操作记录下来,如果为0, 则表示当前COM对象已经销毁了,则需要将其信息从跟踪表中删除。

为了实现上述的拦截,需要解决两个问题:一是如何在程序运行中动态 的生成拦截函数Hook_AddRef(...)和Hook_Release(...);二是如何使 拦截后的新函数Hook_AddRef(...)和Hook_Release(...),能够找到拦 截前的旧函数AddRef(...)和Release(...)。下面,本发明实施方式对如 何解决这两个问题进行详细阐述。

更具体地,在运行的程序中,一个函数就是一段可执行的内存,函数地 址就是该段内存的地址。因此,为了生成拦截函数Hook_AddRef(...)和 Hook_Release(...),需要分别创建对应于拦截函数Hook_AddRef(...)和 Hook_Release(...)的可执行代码段。

图4为根据本发明实施方式为生成Hook_AddRef(...)和Hook_Release (...)而创建的可执行代码段示意图。

要为被监控的COM对象生成替换函数Hook_AddRef(...)和 Hook_Release(...),就是创建两块可执行代码段(代码段在运行中将保存 到内存中),并为其填充可执行的二进制机器码。而且,这段可执行的二进 制机器码可以使用内联汇编语言编写,其所完成的操作是先调用被监控 COM对象的原始的AddRef(...)和Release(...),然后将在调用AddRef (...)过程中的引用计数加1操作记录以及与引用计数加1相关的调用栈信 息保存到COM对象跟踪表中;并当该COM对象的引用计数不为零时,将 在调用Release(...)过程中的引用计数减1操作记录以及与引用计数减1 相关的调用栈信息保存到COM对象跟踪表中。

原始的AddRef(...)和Release(...)也是一段可执行的内存,在替换 过程中,Hook_AddRef(...)和Hook_Release(...)实际上并不需要详细了 解AddRef(...)和Release(...)内部的具体逻辑。

在替换开始时,根据C++的二进制标准,通过对象指针外加一个固定的 偏移分别取得AddRef(...)和Release(...)的指针地址。然后,将这两个 地址分别存储在替换函数Hook_AddRef(...)和Hook_Release(...)中所 涉及的可执行内存中,比如将其放在尾部。这样,在替换函数Hook_AddRef (...)和Hook_Release(...)的相应内存中就分别具有了AddRef(...)和 Release(...)的指针地址,因此Hook_AddRef(...)和Hook_Release(...) 能够顺利寻找到拦截前的旧函数AddRef(...)和Release(...)。

此时在为替换函数Hook_AddRef(...)和Hook_Release(...)创建可 执行内存时,需要多申请两个指针的空间。

由于COM标准要求AddRef(...)和Release(...)都必须是stdcall函 数,因此为了保证这段可执行内存可以替换原始函数,需要将其用内联汇编 语言伪装成一个stdcall函数。

图5为根据本发明实施方式的COM对象的监控装置结构图。

如图5所示,该装置包括拦截函数创建模块501和监控模块502。

其中:拦截函数创建模块501,用于为待监控COM对象的虚函数创建 拦截函数;

监控模块502,用于通过所述拦截函数调用所述虚函数,并将在该调用 过程中的所述待监控COM对象的引用计数操作记录及所述引用计数操作对 应的调用栈信息保存到COM对象跟踪表中。

优选地,该系统进一步包括COM对象跟踪表创建模块503,用于创建 COM对象跟踪表。

在一个实施方式中,拦截函数创建模块501,用于分别为待监控COM 对象的虚函数AddRef和Release创建拦截函数。此时,监控模块502,用于 通过虚函数AddRef的拦截函数调用该虚函数AddRef,并将在该调用过程中 的引用计数加1操作记录以及与引用计数加1对应的调用栈信息保存到 COM对象跟踪表中;并通过所述虚函数Release的拦截函数调用该虚函数 Release,当该COM对象的引用计数不为零时,将在该调用过程中的引用计 数减1操作记录以及与引用计数减1对应的调用栈信息保存到COM对象跟 踪表中,并当该COM对象的引用计数为零时,将该待监控COM对象从COM 对象跟踪表中删除。

优选地,COM对象跟踪表具体可以包括:指向待监控COM对象的内 存地址的对象指针、引用计数操作记录及与引用计数操作相关的调用栈信 息,等等。

在一种实施方式中,拦截函数创建模块501,进一步用于将待监控COM 对象的虚函数AddRef和Release的拦截函数分别伪装为stdcall函数并在所 述待监控COM对象的虚函数AddRef的拦截函数中保存所述虚函数AddRef 的地址,并在所述待监控COM对象的虚函数Release的拦截函数中保存所 述虚函数Release的地址。监控模块502,还用于将引用计数为零的COM对 象从所述COM对象跟踪表中删除。

综上所述,在本发明实施方式中,创建COM对象跟踪表,为待监控 COM对象的虚函数创建拦截函数,而且通过所述拦截函数调用所述虚函数, 并将在该调用过程中的所述待监控COM对象的引用计数操作记录及所述引 用计数操作对应的调用栈信息保存到所述COM对象跟踪表中。由此可见, 通过跟踪每个COM对象的“引用计数”变化情况,将应用程序中影响COM 对象生命期的逻辑点在代码级别记录下来,可以定位运行过程中产生的无法 销毁的COM对象,并追查原因,进而解决COM对象引用计数失衡引发的 一系列系统问题,因此实现了对COM对象的有效跟踪,并可以优化系统资 源。

以上所述,仅为本发明的较佳实施例而已,并非用于限定本发明的保护 范围。凡在本发明的精神和原则之内,所作的任何修改、等同拦截、改进等, 均应包含在本发明的保护范围之内。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号