http://www.visual-graph.com我一直搞不懂为什么会出现垃圾回收这种技术。直到最近。以前我以为自己用标准的ActiveX接口编写的控件一定能够适应不同的编程语言,结果在不同的语言中却发生各种奇怪的现象。首先,为了让vb能够识别我的类库对象,我的属性类型不能是IDispatch的派生类,而必须是IDispatch,vb才能识别,这样我知道,vb原来是后期绑定,它只对Variant这种变体操作,在运行中解释执行!这样就让某些使用其它工具的程序员有点小小的不爽,因为必须对对象做一个强制转换才行。但这是一种宿命,没办法,组件开发商必须这么做才能通用,因此,使用组件的程序员就只好将就一下了,好在这也不是什么繁琐的事情,仅仅是有一点点小小的繁琐而已。有些标准接口,如BSTR(宽字符串)是一定要在ActiveX中创建的(SysAllocString),但你不能释放它,释放是调用者做的事情。所有的编程语言都懂得要用SysFreeString这个函数用来释放你分配的BSTR字符串。所以我们不用担心自己分配的内存会不会造成内存垃圾。但是,对象就没有这么幸运了!我在ActiveX中建立的对象接口,当它被其他编程语言引用的时候,各种编程语言就开始乱来了!VC和VB要简单一点,只要在它应用你的对象时,增加这个对象的引用计数(AddRef)就可以了,VC和VB会自动释放它,通过减少一个引用计数(Release)来完成匹配。Delphi呢?基本上也是这样的,之所以说基本上,是因为在某些特殊的地方它却不会自动减少一个引用计数。这种情况在你引出的对象是一个属性的时候有时候会发生,但我目前还没发现究竟是哪些特殊的情形!(vc里面没有属性的概念)C++Builder最糟,靠,它绝对不会在引用你的对象之后减少一个引用计数!所以,使用这种语言,引用ActiveX对象的时候,就会出现内存垃圾!我这里强烈建议使用C++Builder的程序员,当你使用别人的ActiveX控件访问它的对象的时候,你一定要看看内存有没有泄漏!我真的很怀疑!我的产品是一个ActiveX控件,它要被应用在不同的编程语言中,可是却在C++Builder和Delphi中出现了内存的麻烦,怎么办?为了对付这个头疼的问题,我决定迁就Microsoft,让我的ActiveX控件在VC和VB中间自如地使用,而不出现内存问题。虽然我的程序是用C++Builder开发的,但我还是觉得Microsoft的产品虽然比较笨,但它确实够标准。Borland为了让程序员高兴,接口中有很多实用化的简单的东西,但却不够标准,只有Borland自己的开发工具能够充分利用这种“非标准化”带来的特殊好处。于是,我只好在ActiveX编写中添加了自己的“垃圾回收”机制。
C++Builder和Delphi不是不能自如地释放某些对象内存吗?
我便把那些没有释放的内存管理起来(我的程序当然知道哪些对象还没释放),在某些时刻清理一遍。所幸运的是,由于我的对象特别特别小(每个对象最多只有8字节),这种清理工作,我放到了程序退出的时候进行,应该没有问题了。作为一个程序员,我真的无法容忍任何内存泄漏,哪怕只有几个字节!呜呼!Microsoft 的.net技术就是为了兼容各种不同的编程语言,所以我怀疑垃圾回收技术的出现就是因为不同公司的编程语言在接口方面出现不兼容问题,欲寻求解决办法而出现的!是不是这样?我也不敢肯定!其它内容,请登陆http://www.visual-graph.com

解决方案 »

  1.   

    Delphi呢?基本上也是这样的,之所以说基本上,是因为在某些特殊的地方它却不会自动减少一个引用计数。这种情况在你引出的对象是一个属性的时候有时候会发生,但我目前还没发现究竟是哪些特殊的情形!(vc里面没有属性的概念)没碰到过这回事啊
      

  2.   

    那只是你的ActiveX退出,不是应用程序退出,
    当你的ActiveX unload的时候,
    说明用户已经释放了你的library里的所有的对象的引用,
    那何来未回收的垃圾?
      

  3.   

    当ActiveX unload的时候,用户减少了引用次数,但不至于释放。
      

  4.   

    不会吧,当一个对象的引用次数为0时,它会自动释放自己的,不是吗?
    只有当所有的对象的引用都为0时,COM才会询问你的ActiveX是否需要Unload
    如果有尚未完结的应用,COM是不会unload你的ActiveX的,
    也就是如果用户忘了Release,那么你的ActiveX Library将存活到用户进程退出的时候
      

  5.   

    我的ActiveX控件里面涉及很多com对象,有时候,ActiveX的引用计数变为0了,但是com对象得引用计数可能还没有变为零。举个不恰当的例子,当你在使用我的一个内部com对象得时候,调用了AddRef()函数,这个对象到最后引用计数肯定不是0。这个工作怎么办?只有自己办。你也许会说,谁让用户乱调用AddRef()了?那是它的错!
    但是,其实,各种语言在AddRef和Release方面的操作是不一样的。
    例如,我前面说过了,vc和vb对引用的 对象只负责Release(它要求你自己在ActiveX中写AddRef这一句)。
    而C++builder对应用的对象先要AddRef然后再Release。你看,这就是问题所在,为了照顾不同的编程语言。我们在做ActiveX中的com对象引用的时候,最好统统来一个Addref()(否则vc和vb调用的时候就跨掉了)
    然后,为了考虑C++Builder和Delphi,我们自己到最后必须写一个自己的垃圾回收程序!我现在还没找到更好的办法,反正我们办法,只好在组件内部自己写了垃圾回收程序。
      

  6.   

    按你的说法,COM的跨语言都变成一句空话了>>当你在使用我的一个内部com对象得时候,调用了AddRef()函数,
    >>这个对象到最后引用计数肯定不是0我用完了,我肯定得调用_Release,为什么“这个对象到最后引用计数肯定不是0”?没有很好的理解你的意思,难道AddRef和Release不是成对使用的吗?
      

  7.   

    不需要如此吧,COMOBJ单元实现的代码中好象有明显的IUNKNOWN实现,在_release 中有自动的检测。。
      

  8.   

    问题不同的语言对这个事情处理的方法不一样。
    vc++对IDispatch构造成类的时候,并不执行AddRef(),因为它默认你在编写COM的时候已经AddRef()了。vc在释放这个类对象时要执行Release()。Delphi和C++Builder就不一样,它们每次使用一个对象的时候就AddRef(),然后就Release()。因为他们没有做vc那样的构造函数,而是直接使用IDispatch。
      

  9.   

    觉得你说得不对,Delphi也是遵循COM约定的
    应该是你搞错了