none
Does Marshal.FinalReleaseComObject releases the COM object instantly RRS feed

  • Question

  • I have a .NET application that uses a heavy COM object. Currently, I keep the object in memory once it is created, because of which the Private Memory Set increases by 50 MB for the application.

    To improve the overall memory consumption of the app, I thought I would free up this object after every use. So I tried using the Marshal.FinalReleaseComObject() method to release this COM object but did not see any memory going down. I even tried using the GC.Collect() after the final release call but it did not make any difference either. Is it possible to free the memory occupied by COM object and see a drop in mem usage instantly? Will there be any negative impact of this approach (allocating and freeing frequently ~ 50MB object)?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Wednesday, August 10, 2011 7:36 AM

Answers

  • FinalReleaseComObject is for .Net to tell the OS that there's no longer a need to keep the object around on account of the .Net application. But that doesn't change that it's still upto the OS to release it whenever it wants to. I'm not familiar enough with the algorithm Windows uses to release memory allocated for COM objects to know for sure.
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 6:50 PM
  • I'll post without having read all of the replies.  Pardon me if this was covered:

    As you have seen, actual COM object destruction is beyond the scope of the calling code.  While it is ideal for the object to destroy itself once the reference count drops to zero, it is also at the developer's discretion to do so.  For example, an MS Office application like Excel.  If you create the object Excel.Application and then release it, most likely the object is destroyed promptly, but before releasing it just set its Visible property to true.  Now the story is a different one:  Excel.exe continued to run and the object continues to exist, and this is perfectly acceptable behavior and cannot be catalogued as a bug.

    So bottom line:  While in your particular case you might be experiencing a bug, you cannot judge this as a bug by just quoting the rules of COM.


    MCP
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 6:53 PM
  •  

    Task manager shows working set memory and not the actual memory used. This memory is the allocated memory and not the used memory. Adding further some memory from the working set can be shared by other processes /applications. So the working set memory can big in amount than actual memory used.

     

    You can follow the links I provided in last reply to determine the actual memory used.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Monday, August 15, 2011 2:58 AM
  • After further analysis, I found some memory leaks in the COM component. The developer of the COM component has been notified so that is taken care of now.

    The only question that is left unanswered is whether I should expect the COM Component to release its memory when the FinalReleaseComObject() is called on it?
    Again: "If the memory cannot be reclaimed (using FinalReleaseComObject) and also its not mandatory for the COM component to release itself when counter reaches ZERO then this issue can be closed. But can I get some sort of confirmation on these points so that I can be sure that I did the right thing and there is not much I can do about it?" 


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 3:43 PM

All replies

  • The documentation says that it is out of your control if the actual COM object is unloaded and memory freed.

    http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.finalreleasecomobject.aspx

    If you use a wrapper and it implements IDisposable you can call it and it may help free up memory.


    Wednesday, August 10, 2011 11:03 AM
    Moderator
  • The documentation says: "When the reference count on the COM object becomes 0, the COM object is usually freed, although this depends on the COM object's implementation and is beyond the control of the runtime"

    Which means *ideally* (why *usually* in documentation) the COM object must be freed and memory released when the counter reaches ZERO. If I know the developer of the COM component, can I ask him to review his release code for a possible bug?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Wednesday, August 10, 2011 11:14 AM
  • Since documentation is vague on this it is impossible to say if it is due to a bug in the COM component.

    I don't find much about how the unloading is working, maybe someone else will have more insight to give clue why it may stay in memory.

    Wednesday, August 10, 2011 12:17 PM
    Moderator
  •  

    Hi,

     

    CLR can only control to allocate and release objects in GC heap, the documents says the method can release the managed referenced to COM objects. Yes, CLR can release objects in managed heap, but can not release unmanaged memory. I think you'd better contact with author of the COM component to check the memory release.

     

    Moreover, if the objects are allocated by the methods: Marshal.AllocCoTaskMem Method or Marshal.AllocHGlobal Method, we need to release them in specified way:

    Marshal.FreeCoTaskMem Method

    Marshal.FreeHGlobal Method


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, August 11, 2011 3:07 AM
  • "method can release the managed referenced to COM objects"

    Right. The method releases the managed reference and sets the usage counter of the COM Component to ZERO. The wiki page on COM says that "A COM object is responsible for freeing its own memory once its reference count drops to zero.". So if the memory is not getting freed after a call to FinalReleaseComObject() then I think there is a problem with the COM component itself?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Thursday, August 11, 2011 5:16 AM
  • Yes, you have got the point.

    Moreover, we can follow the link below to check the memory leak.

    Detecting .NET application emory leaks

    Memory Leak Detection in .NET

    Memory Leak

     

    Once we have confirmed that there is a memory leak, it's time to investigate the root problem of the memory leak. We will divide our journey to the solution in 3 phases what, how and where.

    • What: - We will first try to investigate what is the type of memory leak, is it a managed memory leak or an unmanaged memory leak.
    • How: - What is really causing the memory leak. Is it the connection object, some kind of file who handle is not closed etc?
    • Where: - Which function / routine or logic is causing the memory leak.

    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, August 12, 2011 2:28 AM
  • Apart from everything else, you're assuming that Windows will immediately release that 50MB back to the system and remove that memory used by your app. That's a highly dubious assumption if Windows has decided that your working set should include that 50MB or there is no memory pressure on the system to reduce in-use memory. So even if all this COM is already working perfectly there is no guarantee that Windows will give 50MB back to the system.


    Phil Wilson
    Friday, August 12, 2011 7:44 PM
  • Does that mean the values shown in the "Private Working Set" column of Task Manager is not the actual usage at that time?

    If an application momentarily used a heavy 100MB object and frees it (by calling FinalReleaseCOMObject etc methods), the Task Manager will still show that the application is using 100MB+ giving an impression that the app is holding on to large objects and having high memory usage?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Saturday, August 13, 2011 4:15 AM
  •  

    Task manager shows working set memory and not the actual memory used. This memory is the allocated memory and not the used memory. Adding further some memory from the working set can be shared by other processes /applications. So the working set memory can big in amount than actual memory used.

     

    You can follow the links I provided in last reply to determine the actual memory used.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Monday, August 15, 2011 2:58 AM
  • I'll try it out and see if I can find any memory leaks in the app.

    If the COM Component is not freeing up the component even after the counter reaches ZERO then will this behavior count as memory leak? Ideally, Perfmon should show a drop in unmanaged memory when the FinalReleaseComObject() method is called on the COM Component?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Tuesday, August 16, 2011 7:16 AM
  •  

    COM referenced objects are the same as other managed objects. GC would collect unreachable objects in GC heap. So the referenced counter reaches Zero means that the object is unreachable, it would be collect when next GC happens.

    In your case, you need to ensure what causes the memory leak, unmanaged memory or managed memory. CLR or GC can not control memory release in unmanaged memory.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, August 17, 2011 3:30 AM
  • It does not need to count as a memory leak. For example if there is no unmanaged code that calls CoFreeUnusedLibraries () then you'll still have the COM Dll loaded into your process. If the COM object is created by an out-of-process server it's even more complicated because ref counts are cached to avoid processes coming and going every time a ref count goes to zero and then up again.

    I can't help but think you're worrying about this too much. An actual memory leak is one thing, but assuming you can change Windows memory management to release memory in your process that is not actually causing any problems is not worth it. If you really want to limit your process memory, look at job objects and their memory quotas.


    Phil Wilson
    Thursday, August 18, 2011 5:22 PM
  • This question came up because of a memory issue filed against the product I work on. The product uses this COM control for an operation say 'opA'. Now users see a spurge in memory when opA is executed, which is mostly because it uses this COM component.

    What I can do is:

    1. Tell users that its not my fault (product's fault) and its because of the COM component and they will continue to see the memory go up during opA.
    2. Investigate if I can somehow drop the memory used by the COM component after opA completes OR tell the other developer that there seems to be a problem with his component (which is why this thread was opened).

    If the memory cannot be reclaimed (using FinalReleaseComObject) and also its not mandatory for the COM component to release itself when counter reaches ZERO then this issue can be closed. But can I get some sort of confirmation on these points so that I can be sure that I did the right thing and there is not much I can do about it?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Monday, August 22, 2011 9:31 AM
  •  

    You can use CLRProfiler to determine how much managed objects used in the process. Then check that whether the managed memory is released. I think the issue is almost caused by the COM component(unmanaged memory).

    I don't know the result when you follow the link I provided. It can help you ensure whether the issue is  caused by the COM component.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 23, 2011 6:15 AM
  • Paul,

    I was out for the last couple of days. I will surely work on the links this week and post the results.


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    Wednesday, August 24, 2011 5:43 AM
  • To be specific, the application is a MS Office Excel AddIn that uses both managed and un-managed components.

    I tried the Performance Monitor and the Debug Diagnostics Tool to see if there is any memory leak in the my application but could not find much in the analysis report.

    Performance Monitor shows an increase in the Private Bytes and Private Working Set when an operation is run for the first time. It settles down after that and there is very small increase and drop when the operation is re-executed. The "# bytes in all heaps" shows a number of sharp increases an drops during the operation.

    Debug Diagnostics Tool Results on EXCEL.EXE

    WARNING - DebugDiag was not able to locate debug symbols for MSO.DLL, so the reported function name(s) may not be accurate.
    MSO.DLL is responsible for 22.15 MBytes worth of outstanding allocations. The following are the top 2 memory consuming functions:
    MSO!Ordinal6797+501: 15.38 MBytes worth of outstanding allocations.
    MSO!Ordinal862+282: 6.75 MBytes worth of outstanding allocations.

    Though the MSO.DLL is responsible for 22.15 MB of outstanding allocation, I was not able to pinpoint the exact method because no PDB files are available for Office.

    Apart from MSO.DLL, the report also displayed warning for gdi32.dll, I am investigating it.

    The report also highlighted fragmentation> "Detected symptoms of high fragmentation in the following heaps" 0x00320000 (Default process heap - 97.68% Fragmented) 0x05d00000 (mscoreei!g_ExecutableHeapHandle - 99.99% Fragmented). Recommendation says:

    Heap fragmentation is often caused by one of the following two reasons
    1. Small heap memory blocks that are leaked (allocated but never freed) over time
    2. Mixing long lived small allocations with short lived long allocations

    I am allocating a lot of small byte arrays to hold small picture data (byte[] pic = new byte[300~1000]). Could this be the reason behind fragmentation? How can it be improved?


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.

    • Edited by Abhimanyu Sirohi Tuesday, August 30, 2011 11:51 AM removed links to local system files
    Tuesday, August 30, 2011 11:49 AM
  • After further analysis, I found some memory leaks in the COM component. The developer of the COM component has been notified so that is taken care of now.

    The only question that is left unanswered is whether I should expect the COM Component to release its memory when the FinalReleaseComObject() is called on it?
    Again: "If the memory cannot be reclaimed (using FinalReleaseComObject) and also its not mandatory for the COM component to release itself when counter reaches ZERO then this issue can be closed. But can I get some sort of confirmation on these points so that I can be sure that I did the right thing and there is not much I can do about it?" 


    --Abhimanyu
    Click the 'Vote as Helpful' arrow if this post was helpful.
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 3:43 PM
  • This one is really good discussion. According to me, you must ensure all COM references are disposed (I mean managed references to COM handles) and leave rest to COM component.


    Please mark this post as answer if it solved your problem. Happy Programming!

    Wednesday, August 31, 2011 4:27 PM
  • FinalReleaseComObject is for .Net to tell the OS that there's no longer a need to keep the object around on account of the .Net application. But that doesn't change that it's still upto the OS to release it whenever it wants to. I'm not familiar enough with the algorithm Windows uses to release memory allocated for COM objects to know for sure.
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 6:50 PM
  • I'll post without having read all of the replies.  Pardon me if this was covered:

    As you have seen, actual COM object destruction is beyond the scope of the calling code.  While it is ideal for the object to destroy itself once the reference count drops to zero, it is also at the developer's discretion to do so.  For example, an MS Office application like Excel.  If you create the object Excel.Application and then release it, most likely the object is destroyed promptly, but before releasing it just set its Visible property to true.  Now the story is a different one:  Excel.exe continued to run and the object continues to exist, and this is perfectly acceptable behavior and cannot be catalogued as a bug.

    So bottom line:  While in your particular case you might be experiencing a bug, you cannot judge this as a bug by just quoting the rules of COM.


    MCP
    • Marked as answer by Paul Zhou Friday, September 2, 2011 6:10 AM
    Wednesday, August 31, 2011 6:53 PM