ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

EH搜索     
EH云课堂-专业的职场技能充电站 Excel转在线管理系统,怎么做看这里 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
Excel不给力? 何不试试FoxTable! Excel 2016函数公式学习大典 高效办公必会的Office实战技巧 免费下载Excel行业应用视频
300集Office 2010微视频教程 Tableau-数据可视化工具 精品推荐-800套精选PPT模板,点击获取 ExcelHome出品 - VBA代码宝免费下载
你的Excel 2010实战技巧学习锦囊 欲罢不能, 过目难忘的 Office 新界面 Excel VBA经典代码实践指南
查看: 933|回复: 13

[分享] Office插件开发高级知识----为什么要释放非托管Com资源

[复制链接]

TA的精华主题

TA的得分主题

发表于 2018-8-26 00:13 | 显示全部楼层 |阅读模式
目前,国内Office插件开发的风头正盛,很多VBAer都纷纷加入到vb.net或者C#等托管语言的插件开发大军中,但是大部分人从vba转到托管语言的时候,都没有从理论上学习一下托管语言的特性,直接使用vba代码暴力翻译成托管语言,简单粗暴地在代码中使用,只要代码不报错就认为程序没问题了。

然而,直接在代码中暴力使用Com对象会在托管对象中造成释放问题,引发内存泄漏,严重时可能会导致Excel等宿主程序在退出时报错,为了解决这个问题,我下面简单介绍一下在托管代码中使用非托管Com资源的释放问题。

1、什么是Com对象
Com是微软提出来的在组件程序之间进行交互的标准,以Excel为例:application,workbook,workbooks,sheet,sheets,range等等都是Com对象。

2、为什么要释放Com对象
Office程序是非托管语言编写的,C#之类的托管语言要去操作非托管语言就要解决数据交换的格式和结构问题,微软采用Interop(互操作程序集)来解决这个问题。当托管语言访问非托管语言的时候,CLR会给每个COM对象按每进程生成一个RCW(Runtime Callable Wrappers运行时可调用包装器),并用计数器记录Com对象被引用的次数,每引用一次,计数器加1;每释放一次,计数器减1。这种RCW包装会带来额外的资源开销,当计数器为0的时候,RCW资源才会被释放。所以,如果不释放Com对象,RCW会造成相关内存始终被占用,即使Com对象消失,内存也不会被释放,这就是所谓的内存泄漏。

3、不释放Com资源会有什么问题
除了内存泄漏之外,由于RCW的权限高于应用程序,所以只有当所有的Com资源被释放之后,应用程序的进程才能退出。这就是为什么有些人写完的程序执行完毕之后,后台还会残留Office进程的原因。

4、我没有在代码中释放Com资源貌似程序运行得也挺好,而且msdn在VSTO开发中也没有强调这一点,为什么?
因为如果代码书写得当的话,GC会在后台处理Com的释放问题,同时处理RCW资源。所以在微软MSDN中,只是要求不要丢失对Com资源的引用即可。只要不在代码中使用隐含的Com对象引用,GC是可以处理大部分Com资源释放问题的。

5、既然GC可以解决大部分Com资源释放问题,为什么还要谈这个释放问题呢?
因为GC有些时候不靠谱。依赖GC做资源释放的最大问题是你无法控制资源的释放时机,当你处理了成千上万的单元格、工作表和工作簿之后,你不知道是不是还有足够的内存给你做下一步操作,这会给商业程序开发带来不可预计的风险。此外,Com对象的事件订阅和取消订阅也是个大问题,GC是无法正确处理此类问题的,这会造成严重的内存泄漏。

6、如何手工进行非托管Com资源的释放?
参见下面的代码
10.PNG

注意代码的书写要慎重,不得使用会丢失引用的Com对象,例如下面的代码是一个错误示例
3.PNG

7、手工进行非托管Com资源的释放的坏处是什么?
很明显,你的代码会因显式存储和释放COM代理对象而变得臃肿和不可读。
此外,滥用Marshal.ReleaseComObject,特别是Marshal.FinalReleaseComObject,可能会造成其他程序或插件无法使用某些Com对象。
因此手工释放Com资源对开发人员的素质要求较高。

8、有没有其它的方案?
你可以有以下几个选择:

a.不使用pia或vsto,改用第三方控件,例如npoi之类的。
b.使用SafeComWarpper,为每个Com对象建立一个Dispose。
c.通过ExcelDna调用C API也是个可以考虑的选择。


评分

参与人数 4财富 +10 鲜花 +8 收起 理由
sayhi95 + 3 优秀作品
lipton + 3 值得肯定
huang1314wei + 10 值得肯定
zpy2 + 2 优秀作品

查看全部评分

TA的精华主题

TA的得分主题

发表于 2018-8-26 08:16 | 显示全部楼层
支持一下,论坛需要点干货冲洗一下,不然,整天被求助刷屏

TA的精华主题

TA的得分主题

发表于 2018-8-26 13:25 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-8-26 14:21 | 显示全部楼层
本帖最后由 liucqa 于 2018-8-27 23:00 编辑

最后再补充一点,微软并不赞成在代码中显式地调用ReleaseComObject,这里牵涉到很复杂的原因。
如果你明白其中的深层次问题,不想使用ReleaseComObject的话,也许在Com对象使用完毕之后,调用两次GC来释放它也是个省事的办法。

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
因为从Office2007开始,应用程序会在退出的时候处理泄漏的对象引用,所以,在很多时候,你不会发现内存泄漏之后有什么问题,因此采用上面的方式也可以凑合解决泄漏问题。

当然,这个办法并不是万能的良药,你还需要处理一下其它的问题,以后再慢慢细述。

**************
关于VSTO是否需要调用ReleaseCOMObject的问题,答案如下:
原则上你不需要在VSTO中使用ReleaseCOMObject。VSTO为每一个VSTO Add-Ins创建了一个AppDomain,当卸载VSTO Addin的时候,AppDomian也会被卸载,CLR会卸载与其相关的所有资源。但是特殊情况例外。
例如:你在一个Word中操作了PowerPoint的资源,后者需要使用ReleaseCOMObject来确保application能够正常关闭
同样,需要注意的是,VSTO并不能及时地释放COM占用的资源,这可能会导致大量的内存占用,这一点和第五条谈到的GC的原因是一致的。

TA的精华主题

TA的得分主题

发表于 2018-8-26 14:24 | 显示全部楼层
用VSTO估计好一点吧,都是单例引用为主,一个app用到底

TA的精华主题

TA的得分主题

发表于 2018-8-26 14:30 来自手机 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2018-8-26 15:15 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2018-8-26 23:10 | 显示全部楼层
由于一楼的帖子每次修改都要被审核,为避免麻烦,最新更新的内容请在下面的博客园链接中查看
https://www.cnblogs.com/Charltsing/p/RealeaseComObject.html

TA的精华主题

TA的得分主题

发表于 2018-8-27 07:08 来自手机 | 显示全部楼层
vb.net用xls=createObject("Excel.application"),就算是 xls=nothing,进程管理器里还是有 Excel实例,不知道是不是没回收,照理应该已经没有引用了。

TA的精华主题

TA的得分主题

发表于 2018-8-27 09:06 | 显示全部楼层
个人认为这个最好:为每个Com对象建立一个Dispose。
vb.net默认实现的


vb.net用xls=createObject("Excel.application"),就算是 xls=nothing,进程管理器里还是有 Excel实例,不知道是不是没回收,照理应该已经没有引用了。
在vba中前面有个Set ,在net中是关键字,不能使用的。
有时会碰见,一般我调用Close关掉它。

net说用using子句(自动释放),但不太会用。

点评

PIA中没有实现这个Dispose  发表于 2018-8-27 23:02
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关注官方微信,每天学会一个新技能

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2019-8-22 12:34 , Processed in 0.094492 second(s), 16 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2020 Wooffice Inc.

   

沪公网安备 31011702000001号 沪ICP备11019229号

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:徐怀玉律师 李志群律师

快速回复 返回顶部 返回列表