Discussion:
DirectShow heap memory leak
(too old to reply)
Michael Schwab
2005-01-06 23:16:42 UTC
Permalink
Even though I believe I'm releasing all the DirectShow objects correctly
after usage, I still lose over 1 Mb of heap space every time I run the
sample code (from Pesce, etc.). And Run() still can't find enough space to
run, even the first time.

Note, I see this problem on WinCE4.2 because it has a limited heap space,
but I don't know that it's specific to CE so I'm posting this in both
groups. (WinXP seems to have an unlimited heap.) I'm trying to increase my
heap space under CE, but this leak will always create a limit to the number
of times I could play a movie.

I wrote a function dwHeapFreeSpace(), that returns the currently available
free space in the heap (or at least the largest contiguous space), by doing
a bunch of malloc()/free() calls (in a "binary search" pattern) to see
what's the largest single chunk of memory I can allocate, down to a
resolution of 8kb. (If anybody knows of a better way to query the free
space in the heap, I'd like to hear it).

Here's the DirectShow example code I'm using, with most error checking
removed for brevity. All the calls are successful except for the Run()
call, until the fifth iteration where the CoCreateInstance() call fails. I
use my debugPrint() call to capture the results of dwHeapFreeSpace() between
DirectShow calls. The 2-second Sleep(2000) calls (before the debugPrint()s)
I found were needed to give the COM objects time to settle out their usage
of heap space.
IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
Sleep(2000);
debugPrint(TEXT(" - after
CoInitialize"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
Sleep(2000);
debugPrint(TEXT(" - after
CoCreateInstance"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
// Build the graph.
hr = pGraph->RenderFile(szFilename, NULL);
Sleep(2000);
debugPrint(TEXT(""),TEXT(" - after pGraph->RenderFile -
HeapFree="),dwHeapFreeSpace(),hr,S_OK,S_FALSE);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
Sleep(2000);
debugPrint(TEXT(""),TEXT(" - after pControl->Run -
HeapFree="),dwHeapFreeSpace(),hr,S_OK,S_FALSE);
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
} else {
msgBoxWithAbort(TEXT(" - Run failed"), szFilename);
}
hr = pControl->Stop();
} else {
msgBoxWithAbort(TEXT(" - RenderFile failed"), szFilename);
}
Sleep(2000);
debugPrint(TEXT(" - before
cleanup"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pControl->Release();
pEvent->Release();
pGraph->Release();
pControl = NULL;
pEvent = NULL;
pGraph = NULL;
CoUninitialize();
Sleep(2000);
debugPrint(TEXT(" - after
cleanup"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);



And here's the result of running this code 5 times (first number is the
millisecond timer, all other numbers are printed both in decimal and (hex):

4469650-, HeapFree=, 5619712(0x55c000), 0(0x0), 0(0x0), 0(0x0)
4476363- - after CoInitialize, HeapFree=, 5619712(0x55c000), 0(0x0), 0(0x0),
0(0x0)
4479007- - after CoCreateInstance, HeapFree=, 3522560(0x35c000), 0(0x0),
0(0x0), 0(0x0)
4482683- - after pGraph->RenderFile - HeapFree=, 3391488(0x33c000), 0(0x0),
0(0x0), 1(0x1)
4485141- - after pControl->Run - HeapFree=,
1818624(0x1bc000), -2147024888(0x80070008), 0(0x0), 1(0x1)
4494261- - before cleanup, HeapFree=, 1818624(0x1bc000), 0(0x0), 0(0x0),
0(0x0)
4496887- - after cleanup, HeapFree=, 4571136(0x45c000), 0(0x0), 0(0x0),
0(0x0)


4498411-, HeapFree=, 4571136(0x45c000), 0(0x0), 0(0x0), 0(0x0)
4504937- - after CoInitialize, HeapFree=, 4571136(0x45c000), 0(0x0), 0(0x0),
0(0x0)
4507419- - after CoCreateInstance, HeapFree=, 2473984(0x25c000), 0(0x0),
0(0x0), 0(0x0)
4510923- - after pGraph->RenderFile - HeapFree=, 2342912(0x23c000), 0(0x0),
0(0x0), 1(0x1)
4513249- - after pControl->Run - HeapFree=,
1032192(0xfc000), -2147024882(0x8007000e), 0(0x0), 1(0x1)
4518257- - before cleanup, HeapFree=, 1032192(0xfc000), 0(0x0), 0(0x0),
0(0x0)
4520667- - after cleanup, HeapFree=, 3260416(0x31c000), 0(0x0), 0(0x0),
0(0x0)


4522856-, HeapFree=, 3260416(0x31c000), 0(0x0), 0(0x0), 0(0x0)
4528363- - after CoInitialize, HeapFree=, 3260416(0x31c000), 0(0x0), 0(0x0),
0(0x0)
4530673- - after CoCreateInstance, HeapFree=, 1163264(0x11c000), 0(0x0),
0(0x0), 0(0x0)
4534049- - after pGraph->RenderFile - HeapFree=, 1032192(0xfc000), 0(0x0),
0(0x0), 1(0x1)
4536102- - after pControl->Run - HeapFree=,
16384(0x4000), -2147024882(0x8007000e), 0(0x0), 1(0x1)
4540449- - before cleanup, HeapFree=, 16384(0x4000), 0(0x0), 0(0x0), 0(0x0)
4542745- - after cleanup, HeapFree=, 2211840(0x21c000), 0(0x0), 0(0x0),
0(0x0)


4544027-, HeapFree=, 2211840(0x21c000), 0(0x0), 0(0x0), 0(0x0)
4549652- - after CoInitialize, HeapFree=, 2211840(0x21c000), 0(0x0), 0(0x0),
0(0x0)
4551859- - after CoCreateInstance, HeapFree=, 16384(0x4000), 0(0x0), 0(0x0),
0(0x0)
4555117- - after pGraph->RenderFile - HeapFree=, 16384(0x4000), 0(0x0),
0(0x0), 1(0x1)
4557165- - after pControl->Run - HeapFree=,
16384(0x4000), -2147024882(0x8007000e), 0(0x0), 1(0x1)
4562057- - before cleanup, HeapFree=, 16384(0x4000), 0(0x0), 0(0x0), 0(0x0)
4564256- - after cleanup, HeapFree=, 1163264(0x11c000), 0(0x0), 0(0x0),
0(0x0)


4565585-, HeapFree=, 1163264(0x11c000), 0(0x0), 0(0x0), 0(0x0)
4571273- - after CoInitialize, HeapFree=, 1163264(0x11c000), 0(0x0), 0(0x0),
0(0x0)
4576059-, HeapFree=, 16384(0x4000), 0(0x0), 0(0x0), 0(0x0)

The first time, Run() returned an error code of 0x80070008, which I can't
find anywhere. The rest of the time it returned 0x8007000e, which is
E_OUTOFMEMORY.

In summary, CoCreateInstance allocates 2.097 Mb of heap space each time,
RenderFile uses 131kb, and the failed Run() uses 1.572 Mb then 1.31 Mb then
nothing.

The Releases aren't freeing up all the heap space used, leaving 1.049,
1.311, 1.048, and 1.049 Mb behind for the 4 iterations.

Is there some other Release call I'm missing? Or is it because of the fact
that IMediaControl->Run() is returning an out-of-memory error, and it has
some bug that doesn't release whatever space it allocated if it errors out?

And does the size of the mpg/avi file effect the amount of heap space that
Run() allocates? I'm only using a 1 Mb file in this case, but I'd want to
play bigger movies as well.

Thanks,

Michael Schwab
Thore Karlsen [MVP DX]
2005-01-07 15:19:10 UTC
Permalink
On Thu, 6 Jan 2005 16:16:42 -0700, "Michael Schwab"
Post by Michael Schwab
Even though I believe I'm releasing all the DirectShow objects correctly
after usage, I still lose over 1 Mb of heap space every time I run the
sample code (from Pesce, etc.). And Run() still can't find enough space to
run, even the first time.
[snip code]

It looks like you are releasing the references properly, but in general
I would strongly recommend using CComPtr and CComQIPtr. Then you won't
have to worry about releasing anything, it's done automatically.

What kind of file are you trying to play? The memory leak might be in a
decompressor or another filter that's inserted into the graph.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Michael Schwab
2005-01-07 19:02:01 UTC
Permalink
I managed to increase my heap space to 7.7 Mb, and now the movie will run
just once.
It still loses just over 1 Mb of heap space to the memory leak, so there's
not enough memory to run a second time.

Run() eats up 2.6 Mb of heap for a 1 Mb mpg file, and it seems to need more
for bigger files.

What's CComPtr, etc. - is that MFC stuff? If so, I can't use it, because I
can't create an MFC application with the UML code generator I'm using (or at
least it hasn't been worth it to learn how).

I'm playing several different avi/mpg files from various sources. I've
played the same movie 30 or more times under Media Player, so it's not
showing any significant leakage.

I've got to find some way to plug this memory leak, because playing a movie
just once or a few times is not acceptable to Marketing. If I can't fix it,
I'll have to spawn a separate process to play the movie, and have it exit
when done, so I get a fresh heap each time!

Michael Schwab
Post by Thore Karlsen [MVP DX]
On Thu, 6 Jan 2005 16:16:42 -0700, "Michael Schwab"
Post by Michael Schwab
Even though I believe I'm releasing all the DirectShow objects correctly
after usage, I still lose over 1 Mb of heap space every time I run the
sample code (from Pesce, etc.). And Run() still can't find enough space to
run, even the first time.
[snip code]
It looks like you are releasing the references properly, but in general
I would strongly recommend using CComPtr and CComQIPtr. Then you won't
have to worry about releasing anything, it's done automatically.
What kind of file are you trying to play? The memory leak might be in a
decompressor or another filter that's inserted into the graph.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
The March Hare [MVP]
2005-01-07 20:10:57 UTC
Permalink
Post by Michael Schwab
What's CComPtr, etc. - is that MFC stuff? If so, I can't use it, because I
can't create an MFC application with the UML code generator I'm using (or at
least it hasn't been worth it to learn how).
No, not MFC, smart com pointers. Do you have MSDN Library? Otherwise,
Google is your friend.

As far as your leak, spawning a separate process sounds like a good idea.
Even if there is no leak, on Win CE I expect that incremental growth of the
heap may cause problems.

FWIW, my app doesn't leak memory and I use lots of DShow graphs.

Followup-to set to: microsoft.public.win32.programmer.directx.video
--
Please read this before replying:
1. Learn about newsgroups - http://dev.6581.com/newsgroups.html
2. Trim & respond in-line (please don't top post or snip everything)
3. Benefit others - follow up if you are helped or you found a solution
Thore Karlsen [MVP DX]
2005-01-07 20:38:10 UTC
Permalink
On Fri, 7 Jan 2005 12:02:01 -0700, "Michael Schwab"
Post by Michael Schwab
I managed to increase my heap space to 7.7 Mb, and now the movie will run
just once.
It still loses just over 1 Mb of heap space to the memory leak, so there's
not enough memory to run a second time.
Run() eats up 2.6 Mb of heap for a 1 Mb mpg file, and it seems to need more
for bigger files.
What's CComPtr, etc. - is that MFC stuff? If so, I can't use it, because I
can't create an MFC application with the UML code generator I'm using (or at
least it hasn't been worth it to learn how).
No, they are ATL classes. Search for them on MSDN or Google, and you
should be able to see how/where they should be used.
Post by Michael Schwab
I'm playing several different avi/mpg files from various sources. I've
played the same movie 30 or more times under Media Player, so it's not
showing any significant leakage.
I've got to find some way to plug this memory leak, because playing a movie
just once or a few times is not acceptable to Marketing. If I can't fix it,
I'll have to spawn a separate process to play the movie, and have it exit
when done, so I get a fresh heap each time!
Are you sure that you are not doing anything at all except the code you
posted? I don't see anything that is obviously wrong with it.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Michael Schwab
2005-01-07 21:07:19 UTC
Permalink
Here's my complete code section, exactly as I execute it. I think all I
left out before was the error handling and the IVideoWindow stuff.
BTW, I tried commenting out all the pVidWin lines and the memory leak still
happens the same.
The extra HeapFree calls between all the Release()s show that no heap memory
is released until all 4 objects are released.
Plus, it doesn't seem to matter what order you do the Release()s in.

IGraphBuilder *pGraph = NULL;
IMediaControl *pControl = NULL;
IMediaEvent *pEvent = NULL;
IVideoWindow *pVidWin = NULL;

// Initialize the COM library.
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
msgBoxWithAbort(TEXT("InfoForm"), TEXT("ERROR - Could not initialize
COM library"));
return;
}
Sleep(2000);
debugPrint(TEXT("InfoForm - after
CoInitialize"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
msgBoxWithAbort(TEXT("InfoForm"), TEXT("ERROR - Could not create the
Filter Graph Manager"));
pGraph = NULL;
CoUninitialize();
return;
}

Sleep(2000);
debugPrint(TEXT("InfoForm - after
CoCreateInstance"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
if (FAILED(hr))
{
msgBoxWithAbort(TEXT("InfoForm"), TEXT("ERROR - Could not obtain the
Media Control interface"));
pGraph->Release();
pGraph = NULL;
CoUninitialize();
return;
}

hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
if (FAILED(hr))
{
msgBoxWithAbort(TEXT("InfoForm"), TEXT("ERROR - Could not obtain the
Media Event interface"));
pControl->Release();
pGraph->Release();
pControl = NULL;
pGraph = NULL;
CoUninitialize();
return;
}

hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
if (FAILED(hr))
{
msgBoxWithAbort(TEXT("InfoForm"), TEXT("ERROR - Could not obtain the
VideoWindow interface"));
pControl->Release();
pEvent->Release();
pGraph->Release();
pControl = NULL;
pEvent = NULL;
pGraph = NULL;
CoUninitialize();
return;
}


// Build the graph. IMPORTANT: Change this string to a file on your
system.
hr = pGraph->RenderFile(szFilename, NULL);
Sleep(2000);

debugPrint(TEXT("InfoForm"),TEXT("pGraph->RenderFile"),dwHeapFreeSpace(),hr,
S_OK,S_FALSE);
if (SUCCEEDED(hr))
{
//Set the video window.
pVidWin->put_Owner((OAHWND)hWndMe);
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
pVidWin->SetWindowPosition(20, 40, 304, 280);

// Run the graph.
hr = pControl->Run();
Sleep(2000);

debugPrint(TEXT("InfoForm"),TEXT("pControl->Run"),dwHeapFreeSpace(),hr,S_OK,
S_FALSE);
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);

// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
} else {
msgBoxWithAbort(TEXT("InfoForm - Run failed"), szFilename);
}
hr = pControl->Stop();
} else {
msgBoxWithAbort(TEXT("InfoForm - RenderFile failed"), szFilename);
}
Sleep(2000);
debugPrint(TEXT("InfoForm - before
cleanup"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
Sleep(2000);
debugPrint(TEXT("InfoForm - cleanup
1"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pControl->Release();
Sleep(2000);
debugPrint(TEXT("InfoForm - cleanup
pControl"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pVidWin->Release();
Sleep(2000);
debugPrint(TEXT("InfoForm - cleanup
pVidWin"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pEvent->Release();
Sleep(2000);
debugPrint(TEXT("InfoForm - cleanup
pEvent"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pGraph->Release();
Sleep(2000);
debugPrint(TEXT("InfoForm - cleanup
pGraph"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
pVidWin = NULL;
pControl = NULL;
pEvent = NULL;
pGraph = NULL;
CoUninitialize();
Sleep(2000);
debugPrint(TEXT("InfoForm - after
cleanup"),TEXT("HeapFree="),dwHeapFreeSpace(),0,0,0);
Post by Thore Karlsen [MVP DX]
On Fri, 7 Jan 2005 12:02:01 -0700, "Michael Schwab"
Post by Michael Schwab
I managed to increase my heap space to 7.7 Mb, and now the movie will run
just once.
It still loses just over 1 Mb of heap space to the memory leak, so there's
not enough memory to run a second time.
Run() eats up 2.6 Mb of heap for a 1 Mb mpg file, and it seems to need more
for bigger files.
What's CComPtr, etc. - is that MFC stuff? If so, I can't use it, because I
can't create an MFC application with the UML code generator I'm using (or at
least it hasn't been worth it to learn how).
No, they are ATL classes. Search for them on MSDN or Google, and you
should be able to see how/where they should be used.
Post by Michael Schwab
I'm playing several different avi/mpg files from various sources. I've
played the same movie 30 or more times under Media Player, so it's not
showing any significant leakage.
I've got to find some way to plug this memory leak, because playing a movie
just once or a few times is not acceptable to Marketing. If I can't fix it,
I'll have to spawn a separate process to play the movie, and have it exit
when done, so I get a fresh heap each time!
Are you sure that you are not doing anything at all except the code you
posted? I don't see anything that is obviously wrong with it.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Thore Karlsen [MVP DX]
2005-01-07 21:15:58 UTC
Permalink
On Fri, 7 Jan 2005 14:07:19 -0700, "Michael Schwab"
Post by Michael Schwab
Here's my complete code section, exactly as I execute it. I think all I
left out before was the error handling and the IVideoWindow stuff.
BTW, I tried commenting out all the pVidWin lines and the memory leak still
happens the same.
OK, try commenting out as much as possible, and work backwards. Try just
creating the graph and deleting it. Then try adding the RenderFile(),
etc. Try to find the point where the memory leak starts happening.

Also, using CComPtr/CComQIPtr would _really_ make that code look much
better. :)
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Michael Schwab
2005-01-07 21:56:44 UTC
Permalink
Working backwards is a great idea - here goes:

- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.

So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling pGraph->Release()
doesn't help, and sometimes crashes it (especially under WinXP).

So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
Post by Thore Karlsen [MVP DX]
On Fri, 7 Jan 2005 14:07:19 -0700, "Michael Schwab"
Post by Michael Schwab
Here's my complete code section, exactly as I execute it. I think all I
left out before was the error handling and the IVideoWindow stuff.
BTW, I tried commenting out all the pVidWin lines and the memory leak still
happens the same.
OK, try commenting out as much as possible, and work backwards. Try just
creating the graph and deleting it. Then try adding the RenderFile(),
etc. Try to find the point where the memory leak starts happening.
Also, using CComPtr/CComQIPtr would _really_ make that code look much
better. :)
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Thore Karlsen [MVP DX]
2005-01-07 22:18:31 UTC
Permalink
On Fri, 7 Jan 2005 14:56:44 -0700, "Michael Schwab"
Post by Michael Schwab
- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.
So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling pGraph->Release()
doesn't help, and sometimes crashes it (especially under WinXP).
So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
Let me see if I understand correctly. This example would produce a
memory leak:

CoInitialize();
CoCreateInstance(... &pGraph);
pGraph->Release();
CoUninitialize();

Is that what you are saying? This leaks when absolutely no other code is
executed? If that's the case, there's something seriously wrong with
your system. :)
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Michael Schwab
2005-01-08 00:41:05 UTC
Permalink
Yes, that's what I'm saying.
And I know something is seriously wrong!
How do I fix it?
Post by Thore Karlsen [MVP DX]
On Fri, 7 Jan 2005 14:56:44 -0700, "Michael Schwab"
Post by Michael Schwab
- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.
So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling
pGraph->Release()
Post by Thore Karlsen [MVP DX]
Post by Michael Schwab
doesn't help, and sometimes crashes it (especially under WinXP).
So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
Let me see if I understand correctly. This example would produce a
CoInitialize();
CoCreateInstance(... &pGraph);
pGraph->Release();
CoUninitialize();
Is that what you are saying? This leaks when absolutely no other code is
executed? If that's the case, there's something seriously wrong with
your system. :)
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Thore Karlsen [MVP DX]
2005-01-08 01:20:44 UTC
Permalink
On Fri, 7 Jan 2005 17:41:05 -0700, "Michael Schwab"
Post by Michael Schwab
Yes, that's what I'm saying.
And I know something is seriously wrong!
How do I fix it?
It doesn't look like there's anything you can do about that. It looks to
me like something is corrupted, or maybe there is some bug in DirectShow
or some other code you don't control. I'd suggest a reinstall, and if
that doesn't work you may want to contact Microsoft directly about it.
Give them the smallest example that will reproduce the problem.

If you run the minimal code I posted over and over in a loop, does it
eventually run out of memory? Just to rule out any problems with your
dwHeapFreeSpace function.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Michael Schwab
2005-01-11 22:39:12 UTC
Permalink
Looks like you guys have been running with this thread on your own for
awhile! :-)

As you might have noticed in my "How to increase heap memory for malloc()?"
thread, I'm now using GlobalMemoryStatus() to figure out how much of my 32
Mb application address space is available (AvailVirtual), which is not all
heap space.

Anyway, yes, the 4-line example below does run out of memory eventually.
Since it eats about 1 Mb of the AvailVirtual number each time I run it, I
get about as many runs of the loop as I have Mb available (i.e. 3 to 6
times), before it runs out of memory.

But I've now been enumerating heaps, modules, threads, and processes, and I
know there's very little increase in heap space (and no increase in modules
loaded or space) each time I do the CoCreateInstance loop. However, every
time I run the loop it creates a new thread (priority 248), and then leaves
it running! So if I run it 6 times I now have 6 extra threads in my
process! I don't know if a thread takes a Mb of address space, but it does
seem to in this case!

Anyway, as I've said in my other thread, I've given up on playing movies in
my main process, since I have so little free space even before trying to
play a movie, not to mention this memory leak problem. I'm going to spawn a
new process (with CreateProcess) to play a movie, which will then kill
itself when the movie is done. That should give the movie it's own 32 Mb
address space, and should remove all memory and threads when it exits.

However, I know little about inter-process communication, and I'm afraid the
movie window (being smaller than my main app's window) will jump behind the
main window if the user touchs the main window showing around the movie. Is
there a way to "bring to top" one process over the entire system?

As usual, thanks for your help,
Michael Schwab
Post by Thore Karlsen [MVP DX]
On Fri, 7 Jan 2005 14:56:44 -0700, "Michael Schwab"
Post by Michael Schwab
- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.
So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling
pGraph->Release()
Post by Thore Karlsen [MVP DX]
Post by Michael Schwab
doesn't help, and sometimes crashes it (especially under WinXP).
So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
Let me see if I understand correctly. This example would produce a
CoInitialize();
CoCreateInstance(... &pGraph);
pGraph->Release();
CoUninitialize();
Is that what you are saying? This leaks when absolutely no other code is
executed? If that's the case, there's something seriously wrong with
your system. :)
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Joe Flynn
2005-01-08 00:44:43 UTC
Permalink
Post by Michael Schwab
- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.
So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling pGraph->Release()
doesn't help, and sometimes crashes it (especially under WinXP).
So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
What happens if you change the calls in question to:

HRESULT hr = CoInitialize(NULL);
CComPtr<IGraphBuilder> pGraph;
CoCreateInstance(CLSID_FilterGraph,
NULL, CLSCTX_INPROC_SERVER,

IID_IGraphBuilder, (void **)&pGraph);
CoUninitialize();
Thore Karlsen [MVP DX]
2005-01-08 01:16:45 UTC
Permalink
On Fri, 07 Jan 2005 18:44:43 -0600, Joe Flynn
Post by Michael Schwab
Post by Michael Schwab
- Already had the pVidWin stuff commented out.
- Commented out the Run() and the infinite wait - still have the memory
leak.
- Commented out the Stop() and the RenderFile() - still have the memory
leak.
- Commented out the QueryInterface() for pControl and pEvent, and also their
Release calls - still have the memory leak.
- Commented out the CoCreateInstance() and pGraph->Release() calls - no more
memory leak! (Not surprising because the CoInitialize wasn't using any heap
space anyway, and that's all that was left).
- Uncommented the CoCreateInstance() call but left the pGraph->Release()
call commented out - now the memory doubles to 2.097 Mb, which is the amount
that the CoCreateInstance() call usually takes.
So for some reason the pGraph->Release() is only freeing up exactly half the
space that CoCreateInstance() has allocated. And calling pGraph->Release()
doesn't help, and sometimes crashes it (especially under WinXP).
So what's wrong with my CoCreateInstance() call? Is it that pGraph is a
local (stack?) variable?
HRESULT hr = CoInitialize(NULL);
CComPtr<IGraphBuilder> pGraph;
CoCreateInstance(CLSID_FilterGraph,
NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
CoUninitialize();
Note that you can simplify the above CoCreateInstance() call to this:

pGraph.CoCreateInstance(CLSID_FilterGraph);

But, and there is a BIG BUT here. You don't want to use a smart pointer
is this function like it is being used above. CoUninitialize() is called
before the smart pointer destructur releases the interface, which will
lead to very bad things!

It would be better to pull CoInitialize()/CoUninitialize() outside the
function. It could be done in WinMain() or some place like that. You
only need to do it once per thread anyway.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Sarat Venugopal
2005-01-09 12:49:53 UTC
Permalink
Post by Thore Karlsen [MVP DX]
On Fri, 07 Jan 2005 18:44:43 -0600, Joe Flynn
But, and there is a BIG BUT here. You don't want to use a smart
pointer is this function like it is being used above.
CoUninitialize() is called before the smart pointer destructur
releases the interface, which will lead to very bad things!
It would be better to pull CoInitialize()/CoUninitialize() outside the
function. It could be done in WinMain() or some place like that. You
only need to do it once per thread anyway.
Or better still, use a simple class to manage it and instantiate it before
any of this stuff.

In its simplest form:

struct ComInit
{
ComInit() { ::CoInitialize(0); }
~ComInit() { ::CoUninitialize(); }
};

ComInit comInit;
.... // Instantiate other objects and release them

Sarat Venugopal
--
Huelix Solutions
http://www.huelix.com
Thore Karlsen [MVP DX]
2005-01-09 17:58:41 UTC
Permalink
On Sun, 9 Jan 2005 20:49:53 +0800, "Sarat Venugopal"
Post by Sarat Venugopal
Post by Thore Karlsen [MVP DX]
But, and there is a BIG BUT here. You don't want to use a smart
pointer is this function like it is being used above.
CoUninitialize() is called before the smart pointer destructur
releases the interface, which will lead to very bad things!
It would be better to pull CoInitialize()/CoUninitialize() outside the
function. It could be done in WinMain() or some place like that. You
only need to do it once per thread anyway.
Or better still, use a simple class to manage it and instantiate it before
any of this stuff.
struct ComInit
{
ComInit() { ::CoInitialize(0); }
~ComInit() { ::CoUninitialize(); }
};
ComInit comInit;
.... // Instantiate other objects and release them
Indeed, or use Alexandrescu's ScopeGuard:

CoInitialize(0);
ON_BLOCK_EXIT(CoUninitialize);
.... // Instantiate other objects and release them

This is a very nice, general way of making sure things are cleaned up
automatically.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Tim Roberts
2005-01-11 06:00:32 UTC
Permalink
Post by Sarat Venugopal
Post by Sarat Venugopal
Or better still, use a simple class to manage it and instantiate it before
any of this stuff.
struct ComInit
{
ComInit() { ::CoInitialize(0); }
~ComInit() { ::CoUninitialize(); }
};
ComInit comInit;
.... // Instantiate other objects and release them
CoInitialize(0);
ON_BLOCK_EXIT(CoUninitialize);
.... // Instantiate other objects and release them
This is a very nice, general way of making sure things are cleaned up
automatically.
How do you see that as superior to the singleton global object above? It
certainly doesn't read as naturally, in my opinion.
--
- Tim Roberts, ***@probo.com
Providenza & Boekelheide, Inc
Thore Karlsen [MVP DX]
2005-01-11 14:58:12 UTC
Permalink
Post by Tim Roberts
Post by Sarat Venugopal
Post by Sarat Venugopal
Or better still, use a simple class to manage it and instantiate it before
any of this stuff.
struct ComInit
{
ComInit() { ::CoInitialize(0); }
~ComInit() { ::CoUninitialize(); }
};
ComInit comInit;
.... // Instantiate other objects and release them
CoInitialize(0);
ON_BLOCK_EXIT(CoUninitialize);
.... // Instantiate other objects and release them
This is a very nice, general way of making sure things are cleaned up
automatically.
How do you see that as superior to the singleton global object above? It
certainly doesn't read as naturally, in my opinion.
It's a more generic way of doing the same thing. It doesn't require you
to write a new class, and it's applicable in a lot of other situations
-- pretty much anywhere you want to have automatic cleanup of some sort.
Once you learn what it does, using it, and reading code that uses it,
will be completely natural. I highly recommend learning to use it, it
will make your code _much_ simpler, and much safer/robust.
--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html
Loading...