Beim beenden von ActiveX kommen mehrere MemLeaks
-
Ich habe ein Problem beim ActiveX Verständnis.
Ich habe von Microsoft Seite eine ActiveX in Source namen BUTTON geholt und in DebugModus übersetzt. Ich prüffte noch die Registrierung nach dem eingetregenen OCX. Dann erstellte ich einen Container (SingleDocument App). In der Fkt. CMfcContainerView::OnInitialUpdate() versuche ich ein Objekt zu erzeugen:IUnknown pUnknown;
HRESULT hr;
IClassFactory pClf;IID id;
CLSIDFromProgID(_T("BUTTON.ButtonCtrl.1"),&id);
hr = CoGetClassObject(id,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory(void**)&pClf);if (SUCCEEDED(hr)){
TRACE(_T("CoGetClassObject Ok\n"));
}
else{
TRACE(_T("CoGetClassObject Falsch\n"));
}hr = pClf->CreateInstance(NULL,IID_IUnknown,(void**)&pUnknown);
if (SUCCEEDED(hr)){
TRACE(_T("CreateInstance Ok\n"));
}
else{
TRACE(_T("CreateInstance Falsch\n"));
}
pUnknown->Release();
pClf->Release();Das klappt ja auch, nur wenn ich die Apllikation beende dann kommen laute Memleaks. Also untersuchen ich es weiter und stellte fest dass das freigeben (DEATACH) der DLL das Problem verusacht. Ich fügte noch eine Zeile Code nach dem pClf->Release(); ein Aufruf CoFreeUnusedLibraries(); um meine Teorie zu bestätigen.
Was könnte hier die Ursache sein?
-
Dann schau dochnach, wo die Allokationen erfolgt sind.
Wenn es sich um die normale CRT Ausgabe handelt wird das doch in der Traceausgabe angezeigt.
-
Ich habe gestern noch auf Vista das ganze ausprobiert. Leider ohne Erfolg. Dann dachte ich dass durch Release Version dieses Behoben ist bis ich feststellte dass MemLeaks bei Release nicht angezeigt werden.
So ganz kann ich mir nicht vorstellen dass Microsoft ein ActiveX Beispiel zur verfügung stellt der MemLeaks erzeugt. Bei der ganzen Geschichte fehlt mir die nötige Erfarung mit den COM Komponeten aber so langsam fange ich auch das zu verstehen.
Hier die MemLeaks:
Das einer ist von "pDocTemplate = new CSingleDocTemplate" aus meinem Container aber auch das Sag mir nicht viel.Info: AfxDllCanUnloadNow returning S_OK
Detected memory leaks!
Dumping objects ->
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\plex.cpp(29) : {244} normal block at 0x0037F448, 124 bytes long.
Data: < 7 > 00 00 00 00 00 00 00 00 00 00 00 00 D8 A5 37 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\occmgr.cpp(788) : {243} normal block at 0x0037A5D8, 4 bytes long.
Data: < p0x> D4 70 30 78
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\occmgr.cpp(143) : {242} client block at 0x0037F388, subtype c0, 128 bytes long.
a CCmdTarget object at $0037F388, 128 bytes long
a CCmdTarget object at $0037F388, 128 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {215} normal block at 0x0037F810, 28 bytes long.
Data: < 9Px > AC 39 50 78 05 00 00 00 05 00 00 00 01 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {156} normal block at 0x0037CEF8, 36 bytes long.
Data: < 9Px > AC 39 50 78 09 00 00 00 09 00 00 00 01 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\array_p.cpp(110) : {153} normal block at 0x00379CB0, 20 bytes long.
Data: < 7 > 00 00 00 00 04 CE 37 00 00 00 00 00 CD CD CD CD
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\array_p.cpp(67) : {152} normal block at 0x00379C70, 4 bytes long.
Data: < > 00 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\winfrm2.cpp(59) : {151} client block at 0x00379B70, subtype c0, 192 bytes long.
a CDockBar object at $00379B70, 192 bytes long
a CDockBar object at $00379B70, 192 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\array_p.cpp(67) : {150} normal block at 0x00379B30, 4 bytes long.
Data: < > 00 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\winfrm2.cpp(59) : {149} client block at 0x00379A30, subtype c0, 192 bytes long.
a CDockBar object at $00379A30, 192 bytes long
a CDockBar object at $00379A30, 192 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\array_p.cpp(67) : {148} normal block at 0x0037CFD8, 4 bytes long.
Data: < > 00 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\winfrm2.cpp(59) : {147} client block at 0x00379930, subtype c0, 192 bytes long.
a CDockBar object at $00379930, 192 bytes long
a CDockBar object at $00379930, 192 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\winfrm2.cpp(59) : {145} client block at 0x00379830, subtype c0, 192 bytes long.
a CDockBar object at $00379830, 192 bytes long
a CDockBar object at $00379830, 192 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\bardock.cpp(736) : {144} normal block at 0x003795F0, 176 bytes long.
Data: < .x > 18 95 2E 78 CD CD CD CD CD CD CD CD CD CD CD CD
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {142} normal block at 0x003797D8, 26 bytes long.
Data: < 9Px > AC 39 50 78 04 00 00 00 04 00 00 00 01 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {141} normal block at 0x00379780, 24 bytes long.
Data: < 9Px > AC 39 50 78 03 00 00 00 03 00 00 00 01 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {140} normal block at 0x00379728, 24 bytes long.
Data: < 9Px > AC 39 50 78 03 00 00 00 03 00 00 00 01 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\barcore.cpp(156) : {136} normal block at 0x003794C8, 80 bytes long.
Data: < @ > 00 00 00 00 40 01 00 00 00 01 00 08 00 00 00 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\plex.cpp(29) : {133} normal block at 0x00379410, 124 bytes long.
Data: < 7 7 > 00 00 00 00 20 94 37 00 00 00 00 00 04 CE 37 00
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\plex.cpp(29) : {132} normal block at 0x00379358, 124 bytes long.
Data: < 7 > 00 00 00 00 00 00 00 00 00 00 00 00 C0 92 37 00
d:\5x\c-samples\vc8-activexsamples\containermfcnew\mfccontainerview.cpp(32) : {131} client block at 0x003792C0, subtype c0, 92 bytes long.
a CMfcContainerView object at $003792C0, 92 bytes long
a CMfcContainerView object at $003792C0, 92 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {127} normal block at 0x00379088, 42 bytes long.
Data: < 9Px > AC 39 50 78 0C 00 00 00 0C 00 00 00 01 00 00 00
d:\5x\anc5x\samples\mfccontainer\mainfrm.cpp(16) : {124} client block at 0x0037CC98, subtype c0, 548 bytes long.
a CMainFrame object at $0037CC98, 548 bytes long
a CMainFrame object at $0037CC98, 548 bytes long
d:\5x\anc5x\samples\mfccontainer\mfccontainerdoc.cpp(16) : {123} client block at 0x0037CC08, subtype c0, 84 bytes long.
a CMfcContainerDoc object at $0037CC08, 84 bytes long
a CMfcContainerDoc object at $0037CC08, 84 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\plex.cpp(29) : {122} normal block at 0x0037CB50, 124 bytes long.
Data: < h 7 > 00 00 00 00 00 00 00 00 00 00 00 00 68 C9 37 00
{121} client block at 0x0037CAF0, subtype c0, 32 bytes long.
a CDocManager object at $0037CAF0, 32 bytes long
a CDocManager object at $0037CAF0, 32 bytes long
f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {120} normal block at 0x0037CA10, 162 bytes long.
Data: < 9PxH H > AC 39 50 78 48 00 00 00 48 00 00 00 01 00 00 00
d:\5x\c-samples\vc8-activexsamples\containermfcnew\mfccontainer.cpp(79) : {119} client block at 0x0037C968, subtype c0, 108 bytes long.
a CSingleDocTemplate object at $0037C968, 108 bytes long
a CSingleDocTemplate object at 0037C968, 108 bytes long f:\\sp\\vctools\\vc7libs\\ship\\atlmfc\\src\\mfc\\strcore.cpp(141) : {117} normal block at 0x0037C908, 30 bytes long. Data: < 9Px > AC 39 50 78 06 00 00 00 06 00 00 00 01 00 00 00 f:\\sp\\vctools\\vc7libs\\ship\\atlmfc\\src\\mfc\\strcore.cpp(141) : {116} normal block at 0x0037C898, 50 bytes long. Data: < 9Px > AC 39 50 78 10 00 00 00 10 00 00 00 01 00 00 00 {115} normal block at 0x0037C848, 20 bytes long. Data: < 9Px 9Px 9Px> 04 00 00 00 C0 39 50 78 C0 39 50 78 C0 39 50 78 {114} normal block at 0x0037C7E8, 32 bytes long. Data: f:\sp\vctools\vc7libs\ship\atlmfc\src\mfc\oleinit.cpp(84) : {111} client block at 0x0037C6D8, subtype c0, 68 bytes long.
a CCmdTarget object at $0037C6D8, 68 bytes long
a CCmdTarget object at $0037C6D8, 68 bytes long
{61} client block at 0x00376DA8, subtype c0, 64 bytes long.
a CDynLinkLibrary object at $00376DA8, 64 bytes long
a CDynLinkLibrary object at $00376DA8, 64 bytes long
Object dump complete.
-
Noch etwas festgestellt.
Ich habe die zeilen:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>und
_CrtDumpMemoryLeaks();
in Container als auch ActiveX in InitInstance eingabaut und sehe es auch beim Landen der DLL und nicht wie vorhin nur beim Frigaben.
Eins muss ich noch sagen. Wenn ich das ActiveX übersetze dann erhalte ich warnungen 1> WINVER not defined. Defaulting to 0x0502 (Windows Server 2003). Diese Ignoriere ich erstmal oder soll ich sie leiber nicht?
-
Also ich rate mal:
1. Du verwendest für beide Module die MFC und benutzt die MFC als shared DLL.
2. Du hast eine MFC Anwednung, die irgendwann Dein COM Control lädt und wegschmeißt.Nun passiert folgendes.
1. Deine EXE startet und allokiert eifrig Speicher.
2. Deine DLL (COM) wird geladne und allokiert Speicher
3. Die DLL wird entladen und gibt den Sepicher wieder frei.
4. Im DLLMain Code allerdings steht nun auch, dass Leaks reported werden sollen. Das macht die DLL auch. Allerdings entdeckt, die auch noch den Speicher, den Deine EXE allokiert hat, denn beide Module verwenden die MFC als shared Library und die Debug Verwaltung der Module ist natürlcih für EXE und DLL gleich.Just my 2 cents.
-
Beide Module EXE als auch OCX verwenden MFC und sind mit shared MFC eingestellt gewesen. Aber ich habe etwas gefunden.
Wenn ich beim OCX die die Shared auf static MFC einstelle dann erhalte ich die MemLeks nicht mehr.
Kann es sein dass ActiveX doch nicht mit sharedMFC arbeiten soll?
-
Nein!
Das ist kein Fehler! Das wollte ich Dir sagen.Es gibt keine Leaks. Was vermeintlich als Leaks ausgegeben wird, sind die Allokationen Deiner EXE die später freigegeben werden.
Dadurch, dass Du das eine Modul satisch linkst benutzen beide nun einen anderen Memory Manager... Folge: Keine "pseudo Leaks".
Entlade die DLL erst am Ende und es gibt keine Leaks. Außer denen die wirklich ein Leak sind.
-
Ok, nochmal zusammengefasst.
Die Exe übewacht den Speicher von sich selbst und der DLL.
Die DLL übewacht den Speicher von sich selbst und der Exe.
Das gilt nur wenn beide mit sharedMFC arbeiten.
Dann würde ich noch das Problem verstehen. Ich beende die DLL durch CoFreeUnusedLibraries() und "Pseudo" MemLeaks sind zu erkennen da noch die EXE läuft.Wenn das aber mit dem "Pseudo" Meldungen so ist, würde es für mich bedeuten dass auch die Fkt. LoadLibrary, FreeLibrary ebenfalls solche Meldungen generieren. Es ist aber Sinn OCX,DLL Lade Funktionen die Module zu verwenden und dann wieder freizugeben. Das heisst aber dass ich auch iegedwie solche Meldungen ausblenden müsste denn sonst hätte ich keine Chance bei grösseren Prjekten echte MemLeaks zu finden.
Ich Programmierte das Ganze um (Entlade die DLL erst am Ende und es gibt keine Leaks ) und mache in InitInstance den Code bis CreateInstance und im ExitInstance den Release der beiden Zeiger. Die CoFreeUnusedLibraries lasse ich sgar weg da nach dem beenden sowieso die DLL entladen wird.
Problem gleiches Meldungen.Eingermassen sicher ist es jedoch mit dem Memory Manager das, wie du geschrieben hast, nach der statischen Bindung, die Meldungen weg sind. Das Zeigt jedoch ebenfalls dass in dem OCX Modul keine wirklichen Leaks sind. Oder?
Der Grund für diese ganze Aktion ist dass unsere Projekt mehrere OCXs am anfang lädt und wieder freigibt. Diese Überprüfung gibt für die Existenz der Registirung. Die OCXs erzeuegen mehrere über den Operator new verschiedene Objekte. Das führt dazu dass (glaube einiege 100te) Meldungen ausgegeben werden.
Und so wird das ganze Debugging sehr langsam.
Aber wie auch immer auch ohne diese Übeprüffung sobald die OCX verwendet werden, wird sicherlich das Problem ebenfalls zu finden sein.
-
1. Irre ich mich oder hast Du nicht selber _CrtDumpMemoryLeaks in die DLL eingebaut? Ist das Ganze dann nicht hausgemacht von Dir?
2. Ein Leak ist Speicher der zu diesem Moment nicht freigegeben ist.
3. Da ein LoadLibrary noch nichts allokiert wundert es mich nicht das keine Leaks entstehen.
4. Ein Leak wäre nur dann zu berücksichtigen wenn erbeim Beenden der EXE gemeldet wird.
5. Dir ist klar, ds OCX sehr verzögert wirklich entalden werden, wenn Du nicht explizit CoFreeUnusedLibraries aufrufst.
-
Ich galube wir reden nebeneinender.
Ich versuche es nochmal zu beschreiben:
Ich habe am Anfang den Code (in Kurzform):
CoGetClassObject()
pClf->CreateInstance()
pUnknown->Release();
pClf->Release();in InitInstance in von mir erstellten SingleDoc App verwendet.
Beim Beenden traten MemLeaks auf.Dann schrieb ich nach pClf->Release(); den CoFreeUnusedLibraries() Aufruf.
Siehe da MemLeaks kammen nach der Fkt CoFreeUnusedLibraries Ausführung.Als nächstes löschte ich Punk1 und 2 und habe eine Msg. WM_LBUTTONDOWN geschrien. In der stand (bei jedem Klick wird OCX angezeigt oder zerstört)
if (m_pBtnOCX){
m_pBtnOCX->DestroyWindow();
delete m_pBtnOCX;
m_pBtnOCX = NULL;
}
else{
m_pBtnOCX = new CDButton;
m_pBtnOCX->Create(NULL,WS_VISIBLE|WS_CHILD,CRect(0,0,300,300),this,100);
}
MemLeaks kammen beim Beenden der EXEIch schrieb nach m_pBtnOCX = NULL; den Aufruf CoFreeUnusedLibraries.
Nach der Zerstörung das Freigeben der DLL kammen jedes mal die MemLeaks.Ich fügte bei EXE und OCX den _CrtDumpMemoryLeaks Code ein.
MemLeaks zeigen sich zusätlich beim Aufbau des OCX.
Also schmiss ich es wieder raus.Aus dem ganzen und dem was du geschreiben hast verstehe ich das es mit dem ganzen etwas mit Memory Manager zu tun hat, da als ich den OCX auf statische MFC geändert habe waren keine Memleaks zu sehen.
Für diese Zwecke habe ich das OCX von Microsoft Seite als Sample geholt da ich davon ausgehe dass es keine Fehler hat bzw. für mich wären diese nicht in den nächseten Tagen zu finden. Nur der Container, wie ich schon schrieb, ist meine App. in der ich nur diese Paar Codezeilen die ich hier beschreibe, hinzugefügt habe.
-
Nach zwei Tagen Untersuchung habe ich es endlich gefunden.

Es liegt daran dass der OCX in ihren Solution Properties als multibyte Character Set eingestellt war. Der Container war natürlich in Unicode.
Oh man, oh man, kaum stelle ich es um und schon funktioniert ordnunggemäss!
Keine MemLeaks.Trotzdem Danke für die Unterstützung.
