Memory isn't deallocated - ActiveX control (.NET/C#) used in an MFC application

Anders Olsson 1 Reputation point
2020-10-02T11:08:02.587+00:00

I have a memory problem with a COM/OLE/ActiveX component. But I don't know more than the basics of ActiveX... I'm reaching out to the ActiveX experts here - I'd be VERY grateful for some help!!

I'm doing some maintenance on an old MFC project (a Win32 application) for a customer. The application uses a large ActiveX control - developed in .NET/C# by another group. The control is displayed in container windows (CFormView). Let's say that the Win32 application uses about 10MB and the .NET control 100MB:

1) I start the Win32 application - the process uses 10MB
2) I start a container window with the ActiveX control - the process uses 110MB
3) The container and its ActiveX control is closed/deleted - the process uses 110MB
4) I start a new container with the ActiveX control - the process uses 210MB

The memory isn't freed when the container window and its control is deleted. Perhaps the control is still running. After a couple of iterations, the memory consumption gets out of hand.

The ActiveX control is displayed using an ordinary CWnd object. When the container has been created, the control is created with a call to CWnd::CreateControl(). The application calls methods with CWnd::InvokeHelper(), and events from the control is handled via an event sink map. This works/appears-to-work fine. The applications does not import the TLB file. It creates the control based on it's registered name (linked to the control's DLL), and it uses IDispatch::GetIDsOfNames() to get the dispid of the methods to invoke.

The control has no "persistence"; we want it to deallocate completely when the dialog is closed. There can be two container windows with the control open simultaneously - the controls should not interfere with each other.

There is no code specifically deactivating/closing ActiveX. The CWnd object gets deleted before destroying/deleting the container. That is usually enough for other types of controls (e.g. a CEdit or a CComboBox); the class destructor destroys the window and deallocates all resources.

There is a lot of documentation about ActiveX, but it's quite confusing if you aren't an expert... Aren't deleting the CWnd object enough to stop the ActiveX control from running and deallocate everything? Should we call some other method before deleting the CWnd object?

Or could this be some error in the ActiveX control - what should I tell the .NET developers? Could they have missed something?

An ideas? I could read and test for ten days without getting any wiser, alas... :-(

/Anders from Sweden

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,358 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,451 questions
{count} votes

1 answer

Sort by: Most helpful
  1. RLWA32 38,956 Reputation points
    2020-10-05T01:12:55.05+00:00

    Its probable that you are seeing the effect of the non-deterministic memory management used by the CLR for managed code.

    I started with the C# ActiveX control sample from MSDN Code Gallery (CSActiveX). After Visual Studio updated the project I modified the CSActiveX class so that it used about 100 MB of memory on the managed heap. To accomplish this I had the class allocate and initialize an array of integers.

    Then I used the MFC New Application template to create an MDI application with CFormView as the base class for the application's view class. The CSActiveX control was created in the Form using CWnd::CreateControl.

    What I noticed was that opening a MDI child window containing the ActiveX control caused the application's memory consumption to increase by approximately 100 MB as viewed in Task Manager. Opening numerous MDI child windows resulted in memory usage of about 1 GB. Closing all MDI child windows did not reduce the memory usage per Task Manager. However, after all MDI child windows had been closed, opening new windows seemed to trigger garbage collection and the applications memory usage dropped sharply.

    For example, MFC application with multiple windows and Task Manager memory usage -
    29949-mfcax-before.png

    30024-tm-before.png

    And now after closing all open MDI child windows and then reopening one child -
    30013-mfcax-after.png

    29909-tm-after.png

    0 comments No comments