Skip to main content
GameDev.net gamedev.net
🔒 Locked

When does Release not release?

Started by Goodlife Aug 3, 2003 at 8:24 AM 62 replies 6.3k views
Original Post
Goodlife
Goodlife
Hi all, Running into a funny problem on my machine. I''m generating multiple vertex buffers each time I load a level... and I''m releasing them when I unload the level. After about four levels, I get "out of video memory" erros when trying to make a new vertex buffer. After some checking, I find that I *am* releasing all the vertex buffers that I make... but in looking in the DirectX SDK for SetStreamSource, I see a suspicious little note that says: This method increments the reference count of the vertex buffer being assigned and decrements the reference count of the previously assigned vertex buffer. When the vertex buffer is no longer needed, set it to NULL. If you fail to do this, the vertex buffer is not released, resulting in a memory leak. Well, at the end of my render loop, I so a SetStreamSource(NULL), just to clean things up... but I still get a leak. Can anyone shed more light on the situation for me?
-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
Goodlife
Goodlife
Hey, where do I go to nominate you for the "Gamedev.net Golden Helpfulness Award?"
-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
biovenger
biovenger
Since I''m not that proficient in windows programming and DirectX I might not be able to help you, although, can you post the names of the method(s) that you use to release the vertex buffers? Also, maybe some code would be good (read SOME, not the whole .cpp, just some).
-----------------------------Final Frontier Trader
Raloth
Raloth
VertexBuffer->Release();
VertexBuffer = NULL;
MakeNewBuffer(VertexBuffer);

At least that''s what I think it means...
____________________________________________________________AAAAA: American Association Against Adobe AcrobatYou know you hate PDFs...
Nik02
Nik02
Make sure you have your own references released, before setting the pointer to NULL.

HINT: Deleting null pointer does not generate an error...
Niko Suni
Pipo DeClown
Pipo DeClown
quote:
Original post by Goodlife
Hey, where do I go to nominate you for the "Gamedev.net Golden Helpfulness Award?"



hahaahhahahaha!
No, really try using the DirectX Debugger.

.lick
Goodlife
Goodlife
Oddly, setting the SetSteamSource to null TWICE fixes the problem. Which just tells me I have a problem somewhere else, or DirectX does.

-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
RhoneRanger
RhoneRanger
This is a general way to make sure that your buffers are released:

#define SafeRelease(x) if(x){x->Release(); x=NULL;}


Then for each buffer


SafeRelease(Buffer);

There is no reason to set stream source to NULL.

TechleadEnilno, the Ultima 2 projectwww.dr-code.org/enilno
don
don
Looping until the reference count drops to zero is asking for trouble. If you have to do this in order to prevent memory leaks, you''re essentially admitting you don''t know what your code is doing.

You have a problem in your app that should be fixed.
Polymorphic OOP
Polymorphic OOP
quote:
Original post by RhoneRanger
This is a general way to make sure that your buffers are released:

#define SafeRelease(x) if(x){x->Release(); x=NULL;}


Then for each buffer


SafeRelease(Buffer);

There is no reason to set stream source to NULL.




Sounds like you don''t have an understanding of COM and reference counting.

He has to call SetStreamSource with a NULL so that directx will stop refering to the interface and decrease the reference count. Otherwise, when HE calls Release, the reference count will be decremented but the count will still be greater than 0 , and therefore the object will NOT be removed from memory. Using "SafeRelease" will not remove the memory leak.
Goodlife
Goodlife
Just a followup... this problem only manifests when I have code optimization turned on in full. So, I guess it''s just a matter of poking around to see what call is getting tossed out because it''s getting considered redundant or whatnot.

-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
RhoneRanger
RhoneRanger
quote:
Original post by Polymorphic OOP
quote:
Original post by RhoneRanger
This is a general way to make sure that your buffers are released:

#define SafeRelease(x) if(x){x->Release(); x=NULL;}


Then for each buffer


SafeRelease(Buffer);

There is no reason to set stream source to NULL.




Sounds like you don't have an understanding of COM and reference counting.

He has to call SetStreamSource with a NULL so that directx will stop refering to the interface and decrease the reference count. Otherwise, when HE calls Release, the reference count will be decremented but the count will still be greater than 0 , and therefore the object will NOT be removed from memory. Using "SafeRelease" will not remove the memory leak.


umm, maybe YOU dont understand.


Set Stream Source does not inherit the IUnkown interface, and does not increase or decrease the reference count. All you are doing is telling DX to not use a stream by setting stream source to NULL.

and yes, if you call SafeRelease for all your COM objects, the reference count will be 0.



[edited by - RhoneRanger on August 3, 2003 10:58:55 PM]
TechleadEnilno, the Ultima 2 projectwww.dr-code.org/enilno
Joe Forhens
Joe Forhens
Someone just pwned someone else :D
Thank you all :)
CpMan
CpMan
quote:
Original post by RhoneRanger
quote:
Original post by Polymorphic OOP
quote:
Original post by RhoneRanger
This is a general way to make sure that your buffers are released:

#define SafeRelease(x) if(x){x->Release(); x=NULL;}


Then for each buffer


SafeRelease(Buffer);

There is no reason to set stream source to NULL.




Sounds like you don''t have an understanding of COM and reference counting.

He has to call SetStreamSource with a NULL so that directx will stop refering to the interface and decrease the reference count. Otherwise, when HE calls Release, the reference count will be decremented but the count will still be greater than 0 , and therefore the object will NOT be removed from memory. Using "SafeRelease" will not remove the memory leak.


umm, maybe YOU dont understand.


Set Stream Source does not inherit the IUnkown interface, and does not increase or decrease the reference count. All you are doing is telling DX to not use a stream by setting stream source to NULL.

and yes, if you call SafeRelease for all your COM objects, the reference count will be 0.

[edited by - RhoneRanger on August 3, 2003 10:58:55 PM]


Ummm......A function can''t inherit an interface. It wouldn''t need to inherit IUnknown to mess with the reference count, you pass it a reference to the vertex buffer anyway, it simply increments the reference count itself.






VSEDebug Visual Studio.NET Add-In. Enhances debugging in ways never thought possible.
VSEDebug Visual Studio.NET Add-In. Enhances debugging in ways never thought possible.
don
don
Direct3D marks a vertex buffer as being "in-use" when you call SetStreamSource. It doesn''t increment the ref count on the COM interface that an application would see.

As long as this "in-use" flag is set the VB will not be destroyed. You can spin on Release all you like, but until another VB (or NULL) is selected into the device via SetStreamSource, your VB isn''t going to be destroyed (and even then it might not until the current frame has been sent to the hdwe). This is what causes the memory leak referred to by the documentation.

I hope that clears up some of the confusion.

RhoneRanger
RhoneRanger
Strange, just out of curiousity, I went through the degubber at the end of an app, and I did not set stream source to NULL, yet my reference count was 0, and all my objects were NULL.

I am curious about this setting stream source to NULL, for what cards is this necessary? for what systems?
TechleadEnilno, the Ultima 2 projectwww.dr-code.org/enilno
Muhammad Haggag
Muhammad Haggag
quote:
Original post by RhoneRanger
Strange, just out of curiousity, I went through the degubber at the end of an app, and I did not set stream source to NULL, yet my reference count was 0, and all my objects were NULL.

I am curious about this setting stream source to NULL, for what cards is this necessary? for what systems?

As far as I know, it''s not necessary for anything. I believe it''s been pointed out before on DIRECTXDEV that this is just a doc bug.
You have this very same smart comment on SetTexture, SetStreamSource, and maybe SetIndices, ...etc.
Just ignore it, I''ve never done that, and I don''t get any memory leaks.

NOTE: I just ran a little test. I got the refCount of one of my VBs right before SetStreamSource''ing, and right after it. SetStreamSource didn''t increment the reference count.


Peace,
Muhammad Haggag

Polymorphic OOP
Polymorphic OOP
quote:
Original post by RhoneRanger
umm, maybe YOU dont understand


I understand completely. You seem extremely confused with COM.

quote:
Original post by RhoneRanger

Set Stream Source does not inherit the IUnkown interface, and does not increase or decrease the reference count. All you are doing is telling DX to not use a stream by setting stream source to NULL.


NO! Not SetStreamSource. Of course SetStreamSource doesn't inherit IUnkown! That would be impossible. It's a function not a type!

SetStreamSource takes a pointer to a Vertex Buffer as a parameter which is a type which inherits IUnkown. When it does, it increases the reference count of the interface being passed. If you don't SetStreamSource with NULL or pass it another Vertex Buffer then it won't release it. Therefore, when YOU call Release, the reference count will still be greater than 0 and the object will stay in memory.

quote:
Original post by RhoneRanger
and yes, if you call SafeRelease for all your COM objects, the reference count will be 0.


Only if you never increased the reference count! SetStreamSource increases the reference count of the interface and therefore you have to make sure it Releases it as well. Release has to be called once for every time the reference count was increased (not always by you, IE in this case DirectX is in charge of increasing and decreasing reference count when you call the function). This is to ensure that, for instance, if you Release the interface in one module, but another module is still refencing an interface to the object, it will still have a valid reference until that module also calls release. Simply because the macro has the word "Safe" in it and sets the pointer to 0 afterwords/does a 0 check, doesn't change anything at all. All that's doing is making it so if accidentally call SafeRelease with an interface pointer you already "SafeReleased" it won't release it another time or reference an invalid memory location. SafeRelease will not delete the object from memory if it's still being referenced somewhere else (and the count has been increased), just like if you were to just call the Release method manually. This is a good thing because otherwise other modules would have invalid pointers leading major bugs which would be very difficult to track down.

EDIT: If you don't believe me then just RTFM or the quote from it at the beginning of the thread. Anytime DirectX (not just here) stores an interface pointer greater than the duration of a function call it will increase the reference count of the interface. It will also be incharge of calling Release when the user tells it to change what it is refering to. This is a concept fundamental to most COM programming, not just DirectX. Read up on COM if you don't understand.

Anyways, the memory leak is probably at another spot in code, because the interface would be released the next time he called set stream source or when the object containing the reference to the vertex buffer was destroyed.

[edited by - Polymorphic OOP on August 4, 2003 4:13:25 PM]
Muhammad Haggag
Muhammad Haggag
Alright, so once again: On DX9 SetStreamSource doesn''t increment the reference count.

Doing this:
ULONG refCountBefore = pVB->AddRef();
pDevice->SetStreamSource( ..., pVB, ... );
ULONG refCountAfter = pVB->AddRef();
if( 1 == refCountAfter - refCountBefore )
{
MessageBox( ..., "SetStreamSource didn''t increment the reference count", ... );
}

Will give you a message box telling you that it didn''t increment the reference count (the 1 difference is because we use AddRef() to retrieve the reference count)

The comment someone quoted from the docs does not exist in the DX9 docs, I think it was in the 8.1 docs, though.

However, it''s been said that you don''t have to SetStreamSource( NULL ) in 8.1 either, because (I don''t exactly remember):
- SetStreamSource doesn''t increment reference count (as in 9)
OR
- The device does this cleanup when being released.

Peace,
Muhammad Haggag

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.