Re: Memory Lifetime in Interop

From: Sam Gentile [MVP - C#/.NET] (nomail_at_nomail.com)
Date: 03/07/04


Date: Sun, 7 Mar 2004 12:22:14 -0500


>>>>From watching
the memory heap, if I set dynamic_value in the .NET code to be a rather
large value (so it allocates say a 128 Megabyte array), the memory allocated
is 256 megabytes. This is seeming to imply that there are actually two
copies of the array created, one on the managed side (which is marked for
garbage collection when the function returns control to the client) and one
on the COM side into which the data from the managed side is copied. Is
this the case? Or are these shared copies and I am being fooled? If they
are not shared copies, what must the client call to free the memory to
prevent a leak?

>

Safearrays are not isomorphic; in other words they don't have the same
representation on the COM IDL side as they do on the .NET CTS side. For more
insight on why and background see my MSDN article
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/bridge.asp

The Interop marshaler does different things to safearrays depending on
whether you use TLBIMP or VS.NET. When you use VS.NET, the importer does the
equivalent of tlbiimp /safearray. This means that every occurrence of a
SAFEARRAY is converted to a System.Array type. System.Array is the base
class of all .NET arrays and is flexible to handle anything a SAFEARRAY can
handle. So with VS.NET, the COM SAFEARRAY is marshaled to a managed
System.Array and that is what is on the managed heap.Because System.Arrays
can be a hassle to use, TLBIMP.EXE provides a choice for how they are
imported. If you use the /safearray switch the behavior is the same as
VS.NET. If not, all SAFEARRAYs are imported as one-dimensional arrays with a
zero lower-bound.

If a COM component uses SAFEARRAYs that are single-dimensional, use the
tlbiimp without the /safearray switch.

> If they
are not shared copies, what must the client call to free the memory to
prevent a leak?

The types are not the same and the CLR has no idea how to clean up unmanaged
COM types at the right times. The quick answer is Marshal.ReleaseComObject
but the real problem is that COM is deterministic and the CLR isn't. This
means that RCWs are collected whenever the GC runs which may be in a second
or a week from Tuesday. This causes problems with underlying COM types
underneath that need to be freed at deterministic times. I have been writing
in this fro over 2 years:

http://samgentile.com/blog/articles/1987.aspx

http://samgentile.com/blog/articles/294.aspx

http://samgentile.com/blog/archive/2003/04/17/5797.aspx

In my MSDN COM Interop column series, I plan to cover this issue in depth.

-- 
-----
Sam Gentile
Microsoft MVP - C#/.NET
.NET Blog http://samgentile.com/blog/
Please do NOT contact me directly but respond to
the newsgroup instead.
---------
"Doug Semler" <doug_semler@REMOVEMEwideopenwest.com> wrote in message 
news:%23Vz9udFBEHA.2720@TK2MSFTNGP11.phx.gbl...
>I have a question about memory lifetimes with interop, and cannot seem to
> find a definitive answer to the following problem:
>
> We have a .NET assembly which we expose to COM.  The implementation 
> details
> are irrelevent.  The Results structure is a blittable structure.  It is
> important to know that the size of the results structure is only known to
> the .NET object, and it is only known at RUNTIME.
>
>   void GetResults(int ID, out Results[] results)
>   {
>       ...
>       results = new Results[dynamic_value];
>       ...
>   }
>
> When creating a type library for COM, as expected, a signature similar to
> this is emitted:
>
>   ...
>   void GetResults([in] int, [out] SAFEARRAY(Results)** results);
>
>
> When using the code from a COM client the code works as expected; in other
> words the client can access the array values properly.
>
> My questions are regarding lifetime of the returned array.  From watching
> the memory heap, if I set dynamic_value in the .NET code to be a rather
> large value (so it allocates say a 128 Megabyte array), the memory 
> allocated
> is 256 megabytes.  This is seeming to imply that there are actually two
> copies of the array created, one  on the managed side (which is marked for
> garbage collection when the function returns control to the client) and 
> one
> on the COM side into which the data from the managed side is copied.  Is
> this the case?  Or are these shared copies and I am being fooled?  If they
> are not shared copies, what must the client call to free the memory to
> prevent a leak?   CoTaskMemFree (which seems to be the marshaller's
> allocation routines, from what I read), or should it (in this case) have 
> to
> use SafeArrayDestroy(), which will release the objects in the array?
>
> -- 
> Doug Semler
> http://home.wideopenwest.com/~doug_semler
> a.a. #705, BAAWA.  EAC Guardian of the Horn of the IPU (pbuhh).
> I hate spam, standard email address munging applied.
> 42
> DNRC o-
> Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, uneqyl nalbar rira
> erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
>
> 


Relevant Pages

  • Re: not enough storage... error using GetRows
    ... > array only contained ~150,000 rows. ... It took 19 minutes for GetRows to return (db ... and the prog had consumed 200MB of memory. ... The first one allocates some 180MB, the next two only allocate about 47MB ...
    (microsoft.public.vb.database.ado)
  • Re: Framework 2.0 array redim unsatisfactory performance
    ... I am not talking about "array redim" anymore. ... ReDim simply allocates a new ... but I do not even attempt to test its memory ...
    (microsoft.public.dotnet.languages.vb)
  • Memory Lifetime in Interop
    ... I have a question about memory lifetimes with interop, ... When using the code from a COM client the code works as expected; ... My questions are regarding lifetime of the returned array. ...
    (microsoft.public.dotnet.framework.interop)
  • Re: Array Initialization
    ... my @array = split $string; ... through the loop? ... As you can see in the first case it allocates the same memory, ...
    (perl.beginners)
  • Re: CString memory allication question
    ... character array, does the CString class free the memory of the array ... CString at your disposal. ... CString internally allocates its own memory and copies your data. ...
    (microsoft.public.vc.language)