You are currently offline, waiting for your internet to reconnect

How To Turn Off the COM Garbage Collection Mechanism

This article was previously published under Q171414
COM's automatic garbage collection mechanism enables objects in COM serversto reclaim their resource allocations and delete themselves in the eventthat all clients terminate abnormally. Implementation of this mechanisminvolves periodic pings sent from each client machine to each servermachine. There are some situations where it might be desirable to turn offthis pinging to create a "NOPING" COM object. This article discusses thesesituations and also shows a method by which a COM server can turn offpinging for its objects.
When a COM client terminates normally, it releases all references to itsserver object. When a client terminates abnormally however, there might beoutstanding references to the server object. Without a garbage collectionmechanism, the server code has no way of knowing when to reclaim theresources allocated for the COM object, which can then cause a resourceleak. To address this problem, COM implements an automatic garbagecollection mechanism in which the COM resolver process (RPCSS) on theclient machine pings the server machine on behalf of the client process.

A detailed description of the overall garbage collection (GC) strategy andprotocol of COM is beyond the scope of this article. There are, however,many optimizations involved, such that the overhead of pinging even in avery large-scale DCOM system is extremely low. The most basic optimizationsare (a) ping traffic occurs on a machine-to-machine basis, not on a client-to-object basis or on a process-to-process basis; (b) all references fromall clients to all objects are summarized in a single 128-bit value (a"ping set ID"), with only that 16-byte value sent across the network everytwo minutes. In other words, in a steady state, one client holding onereference to one object on a server will generate the same small amount ofping traffic as 1,000 clients holding 10,000 references to 10,000 objectson the same server. (A slightly larger ping message is sent to add orremove objects from the ping set as the set of references varies overtime.) Moreover, alternatives to using COM's GC protocol (for example,using periodic application-level "pings"--method calls that inform theobject that clients are still alive, or using an underlying transportmechanism such as TCP keepalives) are demonstrably much less efficient.Therefore, DCOM's default GC mechanism should be used for any objects thatmust be shut down when their clients disappear or otherwise misbehave ifthose objects would effectively become memory leaks on the server.

The resolver on the server machine keeps track of the pings for each serverobject. The ping period is 2 minutes and, currently, it is non-configurable. When the resolver on the server machine detects that anobject has not been pinged for 6 minutes, it assumes that all clients ofthe object have terminated or otherwise are no longer using the object. Theresolver will then release all external references to the object. It doesthis by simply having the object's stub manager (the COM runtime code thatdelivers calls to each object) call ::Release() on the object's IUnknowninterface. At this point, the object's reference count will be zero so faras the COM runtime is concerned. (There may still be references held bylocal (same-apartment) clients, so the object's internal reference countmay not necessarily go to zero at this point.) The object may then shutitself down.

NOTE: Garbage collection applies to all servers regardless of whethertheir clients are local or remote, or a combination of local and remote.The underlying pinging mechanism is different in the local case as nonetwork packets are generated, but for all practical purposes, the behavioris the same.

There are some circumstances where it is desirable to turn off COM'sgarbage collection mechanism. For example, you might have a statelessobject (for example, a multi-user computational object where all relevantstate is passed as [in] parameters on method calls and the relevant outputis provided as an [out] parameter) or a long-lived object with no per-client-relative state (for example, objects that make up a directory ofother objects) that does not need the ability to detect the liveness of itsclients. Essentially, the kind of object under discussion is one in whichthe internal implementation of the IUnknown::Addref and ::Release() methodsdo not control the object's lifetime; some other mechanism is used todetermine when to shut down the object (if ever). In such situations, itmay be preferable to turn off the periodic pings to eliminate the networktraffic they cause. The following section shows you how to do this viasample code.

It must be kept in mind that garbage collection is done on an object-by-object basis and not on a process-by-process basis. So, if you have aserver process that serves multiple objects (including class factoryobjects) to all clients and you do not want the server machine to be pingedby its clients, then you must turn off pinging for all objects in theserver. As a corollary, while it is perfectly legitimate to disable pingingfor only one or some objects in a process or for all object in one or onlysome processes on a server, the COM pinging protocol is so optimized thatthere will be no significant change in the network bandwidth used by theCOM GC protocol whether there is one or 10,000 DCOM objects in use on amachine-wide basis -- assuming all objects have approximately the samenumber and set of clients. In other words, if there are any other DCOMobjects on a given server using COM's GC/pinging protocol, and thoseobjects are used by roughly the same number and set of clients that areusing an object that might be marshaled "NOPING", there is essentially noadvantage to turning off the pinging protocol with respect to thatparticular object. There will only be a measurable decrease in networktraffic if the clients of the NOPING object(s) are significantly differentfrom the clients of the other objects on the same machine.

Also, it must be noted carefully that garbage collection is an all-or-nothing proposition. If you turn off garbage collection for an object, thenCOM-based lifetime management of the object is turned off also. This meansthat clients can no longer call Release() on their interface pointers andexpect the object to receive the call. Release() called on any proxy is ano-op for such objects. This may seem counterintuitive at first, but it isthe correct behavior because COM can no longer guarantee that the objectwill be shutdown when clients disappear. If ::Release() was enabled in thissituation then the object would find that its reference count went to zerowhen all clients behaved properly but never went to zero if any one clientmisbehaved. This kind of totally unreliable behavior is far worse than thesimple rule that if objects are marshaled with the NOPING flag then withoutexception they will never receive any ::Release() calls from the COMruntime. As an implementation detail, to maximize network efficiency::Release() calls on proxies for objects marshaled NOPING are never sentacross the wire.

Sample Code

You can turn off garbage collection and pinging for an object by marshalingits interfaces with the MSHLFLAGS_NOPING flag. The following sample codeshows how to do this inside the class factory's CreateInstance() function.This is required so that the standard marshaler object gets associated withthe stub manager for the object as soon as the object is created. Anysubsequent calls to CoMarshalInterface() by the stub manager will find thepre-created standard marshaler object.
  STDMETHODIMP  CClassFactory::CreateInstance(LPUNKNOWN punkOuter, REFIID riid,          void**ppv)  {    HRESULT     hr;    IMarshal *pIM = NULL;    IUnknown *pUnknown;    *ppv = NULL;    if (punkOuter != NULL)        return CLASS_E_NOAGGREGATION;    // create our object.    p = new CSimpleObject;    if (p == NULL)        return E_OUTOFMEMORY;    hr = p->QueryInterface(IID_IUnknown, (void**)&pUnknown);    hr = CoGetStandardMarshal(riid, pUnknown, 0, NULL, MSHLFLAGS_NOPING         |MSHLFLAGS_NORMAL, &pIM);    // don't release pIM. All marshals of all interfaces on this object    // from now on will automatically be NOPING    if (FAILED(hr))    {        Message(TEXT("Server: CoGetStandardMarshal Error"), hr);        return(E_FAILED);    }    pUnknown->Release();    hr = p->QueryInterface(riid, ppv);    return hr;  }  // CClassFactory::CreateInstance				

Article ID: 171414 - Last Review: 02/12/2007 18:49:07 - Revision: 3.3

  • Microsoft OLE 4.0
  • the operating system: Microsoft Windows 2000
  • kbdcom kbhowto KB171414