I have been working with d3d11 for quite a while now, and after discovering the directx debugger, i've recently discovered that my program is leaking memory everywhere from all the com objects that aren't releasing properly. After a bit of snooping around and hours of staring at the code, i've developed some methods to isolate where i'm getting these unexpected increases to the ref counts.
first off, all of the objects are wrapped in std::shared_ptrs with custom deleters that call their respective release function. I did this so i would never have to call addref, and the first call to release, the one in the deleter, would only be called when the object went out of scope. It would look something like this:
// in D3D11Renderer.h
...
// declaration
std::shared_ptr<ID3D11Device *> m_Device;
...
// after call to ID3D11CreateDeviceAndSwapChain
m_Device.reset(device, [](ID3D11Device * ptr){ptr->Release();})
Problem is certain random functions in the api calls will just randomly increase the ref count, expecting me to have to deal with it later.
something i found useful in diagnosis was a function that looked like this:
template <typename T>
int getRefCount(T object)
{
object->AddRef();
return object->Release();
}
which, just increments and decrements that count to obtain the current count of refs on that object. Using this, i found that, just before the release in the custom deleter is called, there are 10 outstanding references to the 1 ID3D11Device i created. Curious, i backtracked slowly, calling this function all the way back through the program, right up to where i originally created it. Funny thing, just after i first create the object, (even before the shared_ptr takes ownership), the number of outstanding refs is already 3! This occurs immediately after this here.
result = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, &featureLevel, 1,
D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, NULL, &deviceContext);
if(FAILED(result))
{
return false;
}
this is the first time i call any such function that creates the device, and when i check to see how many refs there are right after, and it says 3! So clearly, I'm misunderstanding something about the way these com objects are supposed to be handled. Is there any such way that i can just manually delete them, rather then use there behind-the-scenes ref counting nonsense?
Every time you create a buffer or a shader or anything that depends on the device, that object will likely contain a reference to the device so will bump up it's reference count to ensure it's not deleted while it is still using it.
It sounds like your approach might well work overall, as you'll essentially keep one single reference to the device in your code to stop it being deleted, and when all your internal references are gone release it. However d3d will still be doing it's own reference counting and so the reference count will only drop to zero when you release every reference to every other related object. Even just creating the swap chain and device will make back buffers and so on that likely need to maintain a reference to the device.
I tried this same idea for a while... And in the end found it much easier to just
#include <atlbase>
Then use
CComPtr<ID311Device> m_Device
as that's pretty much exactly what that class is designed for and it's more lightweight than std::shader_ptr as the objects already have a reference counter in them so there is no need to keep a separate one.
Using shared_ptr is not correct for Direct3D (COM) objects, even if you use custom deleters.
First, COM objects use intrusive reference counting, which means the reference count is stored in the object itself. shared_ptr on the other hand uses non-intrusive reference counting, which means the reference count is stored in the smart poiter object. Therefore, using shared_ptr for COM objects means that you have two separate, independent reference counts: the COM object's, and the shared_ptr's.
Second, using a custom deleter solves the problem of properly releasing the object, but it doesn't solve the problem of properly acquiring a reference to the object. Assigning a COM object to a shared_ptr will increment the reference count of the shared_ptr, but not the object's.
That explains why you're leaking objects: D3D methods increment objects' reference counts, but you are using shared_ptrs that decrement the object's reference count only once for the entire lifetime of the object (when all shared_ptrs pointing to the object are destroyed).
So, you need to use a COM smart pointer, such as ATL's CComPtr.
Related
I am writing code that utilizes COM interfaces. I am basing my code on examples that I have found online. I do not want to utilize smart pointers in this case because I want to understand the basics of COM and not just have a smart pointer class do all of the work for me.
In order to frame my questions, let's assume I have a class similar to the following:
public class TestClass
{
private:
IUnknown *m_pUnknown;
public:
TestClass();
void AssignValue();
}
TestClass::TestClass()
{
m_pUnknown = NULL;
}
void TestClass::AssignValue()
{
IUnknown *pUnknown = NULL;
//Assign value to pUnknown here - not relevant to my questions
m_pUnknown = pUnknown;
pUnknown->Release();
}
Now on to my specific questions.
1) The examples I've seen to not use AddRef() when initializing a value, such as in the class constructor. Does the AddRef() happen "automatically" behind the scenes when a COM pointer is first assigned a value?
2) Although my code example does not show it, it is my understanding that in the AssignValue() method, when you assign a second value to overwrite the value of pUnknown (originally set in the class constructor), Release() is automatically called. After assigning the new value to pUnknown its reference count stands at zero. I need to call pUnknown->AddRef() immediately after the reassignment. Is my understanding correct?
Notes: I assume we are ignoring exceptions for simplicity here. If this was for real, you would want to use smart pointers to help keep things straight in the presence of exceptions. Similarly, I am not worrying about proper copying or destruction of instances of your example class or multi-threading. (Your raw pointers cannot be used from different threads as simply as you might assume.)
First, You need to make any necessary calls to COM. The only way anything might happen "automatically" behind the scenes would be if you were using smart pointers to do them.
1) The examples you refer to have to be getting their COM interface pointers from somewhere. This would be by making COM calls, e.g., CoCreateInstance() and QueryInterface(). These calls are passed the address of your raw pointer and set that raw pointer to the appropriate value. If they weren't also implicitly AddRef'ed, the reference count might be 0 and COM could delete the associated COM object before your program could do anything about it. So such COM calls must include an implicit AddRef() on your behalf. You are responsible for a Release() to match this implicit AddRef() that you instigated with one of these other calls.
2a) Raw pointers are raw pointers. Their value is garbage until you arrange for them to be set to something valid. In particular, assigning a value to one will NOT auto-magically call a function. Assigning to a raw pointer to an interface does not call Release() - you need to do that at the appropriate time. In your post, it appears that you are "overwriting" a raw pointer that had previously been set to NULL, hence there was no existing COM interface instance in the picture. There could not have been an AddRef() on something that doesn't exist, and must not be a Release() on something that isn't there.
2b)
Some of the code you indicated by a comment in your example is very relevant, but can easily be inferred. You have a local raw pointer variable, pUnknown. In the absent code, you presumably use a COM call that obtains an interface pointer, implicitly AddRefs it, and fills in your raw pointer with the proper value to use it. This gives you the responsibility for one corresponding Release() when you are done with it.
Next, you set a member raw pointer variable (m_pUnknown) with this same value. Depending on the previous use of this member variable, you might have needed to call Release() with its former value before doing this.
You now have 2 raw pointers set to the value to work with this COM interface instance and responsibility for one Release() due to 1 implicit AddRef() call. There are two ways to deal with this, but neither is quite what you have in your sample.
The first, most straightforward, and proper approach (which others have correctly pointed out & I skipped passed in the first version of this answer) is one AddRef() and one Release() per pointer. Your code is missing this for m_pUnknown. This requires adding m_pUnknown->AddRef() immediately after the assignment to m_pUnknown and 1 corresponding call to Release() "someplace else" when you are done using the current interface pointer from m_pUnknown. One usual candidate for this "someplace else" in your code is in the class destructor.
The second approach is more efficient, but less obvious. Even if you decide not to use it, you may see it, so should at least be aware of it. Following the first approach you would have the code sequence:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
pUnknown->Release();
Since pUnknown and m_pUnknown are set the same here, the Release() is immediately undoing the AddRef(). In this circumstance, eliding this AddRef/Release pair is reference count neutral and saves 2 round trips into COM. My mental model for this is a transfer of the interface and reference count from one pointer to the other. (With smart pointers it would look like newPtr.Attach( oldPtr.Detach() ); ) This approach leaves you with the original/not shown implicit AddRef() and needing to add the same m_pUnknown->Release() "someplace else" as in the first alternative.
In either approach, you exactly match AddRefs (implicit or explicit) with Releases for each interface and never go to a 0 reference count until you are done with the interface. Once you do hit 0, you do not attempt to use the value in the pointer.
Avi Berger already posted a great answer, but here is the same thing stated another way in case it helps with understanding.
In COM, reference counting is done within the COM object. The COM runtime will destruct and free an object whose reference count reaches 0. (This might be delayed by some time from the point of the count hitting 0).
Everything else is a convention. The usual convention amongst C++ COM programmers is that raw interface pointers should be treated as owning pointers. This concept means that any time a pointer points to a COM object, the pointer owns that object.
Using this terminology, the object may have multiple owners at any one time, and the object will be destroyed when nobody owns it.
However, raw pointers in C++ don't have ownership semantics built in. So you have to implement it yourself by making function calls:
Call AddRef on an interface pointer when that pointer takes ownership of an object. (You'll need to be aware of which Windows API functions or other library functions already do this, to avoid you doing it twice)
Call Release on an interface pointer when that pointer is about to stop owning an object.
The benefit of smart pointers is that they make it impossible for you to forget to call Release when an interface pointer stops owning an object. This includes the following cases:
Pointer goes out of scope.
Pointer is made to stop pointing to the object, by using assignment operator.
So, looking at your sample code. You have the pointer m_pUnknown. You want this pointer to take ownership of the object, so the code should be:
m_pUnknown = pUnknown;
m_pUnknown->AddRef();
You will also need to add code to your class destructor and your class assignment operator to call m_pUnknown->Release(). I would very strongly recommend wrapping these calls in the smallest class possible (that is, write your own smart pointer and make TestClass have that smart pointer as a member variable). Assuming of course you don't want to use an existing COM smart pointer class for pedagogical reasons.
The call pUnknown->Release(); is correct because pUnknown currently owns the object, and the pointer is about to stop owning the object due to the fact that it will be destroyed when the function block ends.
You may observe that it would be possible to remove both of the lines m_pUnknown->AddRef() and pUnknown->Release(). The code will behave exactly the same. However , it is better to follow the convention outlined above. Sticking to a convention helps yourself to avoid errors and it also helps other coders to understand your code.
To put it another way, the usual convention is to think of the pointer as having a reference count of either 0 or 1, even though the reference counting is not actually implemented that way.
First, my apologies. My attempt to simplify my code for the sake of clarity turned out to be misguided. However, I believe my questions were answered. If I may, I will summarize.
1) Any COM object that is assigned a value other than NULL needs to be immediately followed by AddRef() unless the AddRef() was implicitly handled (as is the case with some Windows API calls).
2) Any reassignment of value to a COM pointer, assuming that the "before" value is not NULL must be immediately proceeded by Release(). AddRef() would then by needed as mentioned in #1.
3) Any COM variable whose value needs to be preserved beyond its current scope requires that it have a reference count of at least 1 upon exiting its said scope. This may mean that an AddRef() is required.
Would this be a fair summary? Did I miss anything?
Im trying to start a new thread using CreateThread and pass the pointee of a shared_pointer as an argument. If i was to use good old ATL, it would call Ccomptr's operator () and increase the ref count and eventually retrieve the pointer.
I'm trying to do the same using STL's shared_ptr, but I'm getting an error where conversion between std::shared_ptr to LPVOID doesn't exist.
std::shared_ptr<X> m_pSettings = std::make_shared(new ....);
if (nullptr == (m_hBackgroundThread = ::CreateThread(
nullptr, // default security attributes
0, // use default stack size
ThreadProc, // thread function name
m_pSettings, // argument to thread function
0, // use default creation flags
0)))
{
LOG_ERROR(L"Failed to create thread");
return false;
}
The correct answer, as you have already been told, is to use std::thread:
// Hey, look: No magic nullptrs and zeros nobody ever changes to non-defaults anyway!
std::thread t(ThreadProc, m_pSettings);
// Don't forget to
t.detach();
// if you let the std::thread object destruct without first joining it and making sure
// the thread finishes executing
Not only std::thread solves your problem, it has a multitude of other benefits such as allowing you to pass multiple parameters without fuss, it copies/moves/does-the-right-thing with the arguments you pass, etc. and it doesn't require you to resort to any supposedly clever but actually not hacks. If you use std::async instead of std::thread you can even get in the caller thread the exception that caused the thread function to unwind if there was one.
The alternative of passing CreateThread the address of your shared_ptr and then dereferencing it inside the ThreadProc might work, if you're extremely careful - at the very least you have to make sure the caller's shared_ptr doesn't go away until the ThreadProc is done with it - but that's just asking for bad things to happen.
Sure, if you had no alternatives that's what you do, but given std::thread and friends doing anything else is wrong and a waste of time.
Also, your comparison to ATL seems to be founded on a misunderstanding. The difference is not between ATL's smart pointers that are extra-clever and and are able in some magical way to keep the reference count even when giving you the raw pointer (though I am unaware of an CComPtr::operator()) while C++ standard library smart pointers are lame and don't do that. The difference is between special object who manage keep their own reference count and manage their own lifetimes given that you declare when you use them (i.e. call AddRef) and arbitrary resources.
A smart pointer for COM (be it CComPtr or _com_ptr_t or any half-baked lame class you fine online) is basically a wrapper around the COM object's innate capability to manage its own lifetime.
You could have just as much added AddRed, Release, etc. (with the associated semantics, obviously) to your class X and wrapped it in a COM smart pointer...
You could pass shared_ptr object by pointer like this: &m_pSettings
Then dereference it in your ThreadProc :
std::shared_ptr<X> pSettings = *static_cast<std::shared_ptr<X>*>(lpParam);
Probably you need to copy your shared_ptr first before passing pointer to it into CreateTrhead so it'll be in scope while ThreadProc running.
I think..
Attach and Detach makes no change in the reference count.
But Destructor of CComPtr call release on the pointer it contains.
So is it necessary to call detach every time when one use attach?...
{
CComPtr<IObj> pPtr;
pPtr.Attach(pPtr1);
.....//No detach on pPtr
}
As you mentioned, Attach/Detach don't affect reference counter, by design. So you are to use them when you have a special need to skip adding a reference. Otherwise you initialize the pointer in a more natural way (constructor, assignment operator etc).
Your special need for Attach is typically to compensate external reference already added. So that your CComPtr destructor would correctly release it when it is time to.
So, no, you don't have to pair Attach with Detach. When you have to, you supposedly would not use Attach in first place.
For example, Attach:
{
// We have an oustanding reference on pRawFoo we want to safely compensate for
CComPtr pFoo;
pFoo.Attach(pRawFoo); // No effect on counter, but since here we would release
// the reference going out of scope
// ...
} // ~CComPtr releases the reference as intended
No need in Attach:
{
// External pRawFoo is in proper balance in terms of reference count
CComPtr pFoo;
pFoo = pRawFoo; // No need in Attach, pFoo adds a reference
// ...
} // ~CComPtr releases the reference as intended
Like most smart pointers, CComPtr<T> indicates ownership and uses RAII semantics to ensure that an owned resource is properly cleaned up. The methods Attach and Detach are used to transfer ownership, in part because the reference count bookkeeping can be relatively expensive. So the question you need to answer in your context is what the pattern of ownership is.
When transferring ownership between two CComPtr<T> objects, there will be a tendency to match Attach and Detach calls, but they will be on the separate objects:
spFoo2.Attach(spFoo1.Detach());
Consider the following snippets and what they indicate about ownership of the IFoo object. Both m_spFoo and spFoo are intended to be CComPtr<IFoo> values:
HRESULT C::GetFoo_1(IFoo **ppFoo)
{
return m_spFoo.QueryInterface(ppFoo); // or m_spFoo.CopyTo(ppFoo)
}
HRESULT C::GetFoo_2(IFoo **ppFoo)
{
*ppFoo = m_spFoo.Detach();
return S_OK;
}
spFoo = obj.GetFoo_3();
spFoo.Attach(obj.GetFoo_4());
Here's my take on these snippets.
The first is a very usual way to return an IFoo to a caller, following the usual semantics wherein the caller receives a copy with an incremented reference count.
The second is okay if ownership is being passed to the caller; the caller takes the copy that the C object previously had.
The third is probably returning a CComPtr<IFoo> or CComPtr<IFoo>& already (the non-reference case can lead to extra reference count bookkeeping) and we are indicating further shared ownership; that is, we want to keep it around for longer than that statement.
The fourth indicates unusual semantics in GetFoo_4, as it must have provided a reference count on a raw IFoo* that we don't want to further increment.
In my application, I'm hooking various functions for creating COM objects (such as CoCreateInstanceEx) to get notified whenever some object is created. I'm keeping track of all created objects in a std::list and I'm iterating over that list to do various things (like checking which OLE objects have been activated).
The issue with this is that right now, whenever adding an IUnknown pointer to my list, I call IUnknown::AddRef on it to make sure that it doesn't get destroyed while I'm tracking it. That's not what I really want though; the lifetime of the object should be as long (or short) as it is without my tracing code, so I'd rather like to maintain a weak reference on the objects. Whenever the last reference to some tracked COM object is removed (and thus the object gets destroyed), I'd like to get notified so that I can update my bookkeeping (e.g. by setting the pointer in my list to NULL).*
What's the best way to do this? Right now, I'm patching the (first) VTable of all created objects so that the calls to IUnknown::Release via the first vtable get notified. However, this won't work for COM interfaces which inherit from multiple interfaces (and thus have multiple vtables), but I'm not sure whether this is really a problem: given the Rules for Implementing QueryInterface, there should always be just one IUnknown returned by IUnknown::QueryInterface, right? So I could do that and then patch that vtable.
Furthermore, this approach is also a bit hairy since it involves creating thunks which generate some code. I only implemented this for 32bit so far. Not a big issue, but still.
I'm really wondering whether there isn't a more elegant way to have a weak reference to a COM object. Does anybody know?
*: The next thing I'll have to solve is making this work correctly in case I have active iterators (I'm using custom iterator objects) traversing the list of COM objects. I may need to keep track of the active iterators and once the last one finished, remove all null pointers from the list. Or something like that.
This isn't an answer as much as a set of issues why this is a really tricky thing to do - I'm putting it in as an answer since there's too much information here than fits in a comment :)
My understanding is that the concept of weak reference just doesn't exist in COM, period. You've got reference counting via IUnknown, and that's the sum total of how COM deals with object lifetime management. Anything beyond that is, strictly speaking, not COM.
(.Net does support the concept, but it's got an actual GC-based memory manager to provide appropriate support, and can treat WeakRef objects differently than regular references in memory. But that's not the case with the very simple world that COM assumes, which is a world of plain memory and pointers, and little more.)
COM specifies that reference counting is per-interface; any COM object is free to do ref counting per object as a convenience, but the upshot is that if you're wrapping an object, you have to assume the most restrictive case. So you cannot assume that any given IUnknown will be used for all addrefs/releases on that object: you'd really need to track each interface separately.
The canonical IUnknown - the one you get back by QI'ing for IUnknown - could be any interface at all - even a dedicated IUnknown that is used only for the purpose of acting as an identity! - so long as the same binary pointer value is returned each time. All other interfaces could be implemented any way; typically the same value is returned each time, but a COM object could legitimately return a new IFoo each time someone QI's for IFoo. Or even keep around a cache of IFoos and return one at random.
...and then you've got aggregation to deal with - basically, COM doesn't have a strong concept of object at all, it's all about interfaces. Objects, in COM, are just a collection of interfaces that happen to share the same canonical IUnknown: they might be implemented as a single C/C++ object behind the scenes, or as a family of related C/C++ objects presenting a facade of a 'single COM object'.
Having said all of that, given that:
I'm tracing the state of various components (including all COM objects) of this software for the sake of debugging
Here's an alternate approach that might produce some useful data to debug with.
The idea here is that many implementations of COM objects will return the ref count as the return value to Release() - so if they return 0, then that's a clue that the interface may have been released.
This is not guaranteed, however: as MSDN states:
The method returns the new reference count. This value is intended to be used only for test purposes.
(emphasis added.)
But that's apparently what you're doing here.
So one thing you could do, assuming you own the calling code, is to replace calls with Release() with an inline called MyRelease() or similar that will call release, and if it notices that the return value is 0, then notes that the interface pointer is now possibly freed - removes it from a table, logs it to a file, etc.
One major caveat: keep in mind that COM does not have a concept of weak ref, even if you try to hack something together. Using a COM interface pointer that has not been AddRef()'d is illegal as far as COM is concerned; so if you save away interface pointer values in any sort of list, the only thing you should so with those is treat them as opaque numbers for debugging purposes (eg. log them to a file so you can correlate creates with destroys, or keep track of how many you have outstanding), but do not attempt to use them as actual interface pointers.
Again, keep in mind that nothing requires a COM object to follow the convention of returning the refcount; so be aware that you could see something that looks like a bug but is actually just an implementation of Release just happens to always returns 0 (or rand(), if you're especially unlucky!)
First, you're right that QueryInterface for IUnknown should always return the same pointer; IUnknown is treated as the object's identity IIRC, so needs to be stable.
As for weak pointers, off the top of my head, maybe you could give CoMarshalInterThreadInterfaceInStream a whirl? It is meant to allow you to serialize a reference to a COM object into a stream, then create a new reference to the object on some other thread using the stream. However, if you serialise into a stream and retain the stream as a sort of weak pointer, then unmarshal later on to recover the pointer, you could check whether unmarshalling fails; If so, the object is gone.
With WinRT IWeakReference was added to enable weak refs to COM objects. Objects created with WRL's RuntimeClass support IWeakReference by default (can be disabled with an option).
you can use IWeakReference in your designs but it means you will need to use at least some WinRT concepts, IInspectable based interface.
I came across a leak in a Direct3D application of mine, and I ended up correcting it, but I think the cause of the leak was due to my misunderstanding of how Direct3D handles its memory and interfaces.
I haven't been able to find a definitive article/tutorial on it (please provide one if you have one), but from what I've gathered, it works as such:
Every time you call a Get method, the number of references for the object returned is incremented. So if I call GetRenderTarget, the surface being rendered to has its reference count incremented.
Calling Release on the interface decrements its reference count. These first two points combined essentially mean: every time you get an interface, release it after you're done with it.
When the reference count reaches 0, the instance is deleted.
I'm not entirely sure if this is correct, but it seems to work in practice. If someone could clarify/confirm how it works, that'd be great.
P.S, are there any safeguards implemented in releasing interfaces? Calling Release any number of times on the back buffer doesn't seem to do any damage (which is a good thing, but I'm not sure why it doesn't).
Direct3D is based on COM, which is a technology that's at least 15 years old. Seems many people claim COM is dead and for that reason many overlook it, but reality is that there are many things in windows including Direct3D and MS's new Media Foundation that are all based on COM.
I strongly suggest you take a look at general COM programming. There are plenty of books and resources, but many of them are rather old but that's ok because the root of the technology hasn't changed for a very long time.
Basically what you've observed is interface reference counting. COM is based purely on accessing objects via interfaces, which all derive from the base interface, IUnknown. IUnknown implements methods AddRef() and Release() and it is the responsibility of your application to call AddRef() whenever you store a local copy of a pointer and to call Release() whenever that local copy is no longer needed.
When you have methods with interface out parameters (i.e. IFoo** ppObj ), that means the callee is giving you back an interface and now that you have it, it is still your responsibility to call Release() whenever you are done with it.
Once you get the hang of it, I'd suggest you start using CComPtr smart class for storing local and member variables (still pass raw interface values between function calls, no need for smart pointer parameter types). It will take care of all your reference counting. Also don't make it a practice of calling release "any number" of times. It might work today because the object is implemented as a singleton, or maybe something else is holding on to it, but that might change with next patch or next release. Always follow the rules. If you have an interface, when you don't need it call Release() exactly once. If you made a copy of interface pointer, make sure to call AddRef() exactly once.
The application of addref/release semantics is much wider than COM technology. There is simple rule one CreateObject() (or CreateTexture, or GetRenderTarget, or GetBackBuffer, etc...) have to be confronted with one Release(), one AddRef() have to be confronted with one Release().
In COM IUnknown::Release() returns number of references to object. It may delude you and you can think:
"Hm... I just call Release() until it return 0 and I will have no leaks. ???? PROFIT!!!!!111" <-- That is wrong! AddRef might be called by Direct3D itself or by 3rd_party library you pass this object to, or something else outside your app. One Release for one AddRef. You should call Release when you don't need object anymore, don't waste system resources.
You said:
Calling Release any number of times on the back buffer doesn't seem to do any damage
That means nothing. May be The Universe like you so much or you just too lucky to not get exceptions from D3D.
Smart pointers (such as CComPtr) could make your life much easier if you will use them. In this case you don't need to call Release explicitly, it is called in CComPtr dtor if it is assigned to some object.
void get_surface(IDirect3DDevice9 *pDevice)
{
IDirect3DSurface9 *surf0;
IDirect3DSurface9 *surf1;
CComPtr<IDirect3DSurface9> surf2;
CComPtr<IDirect3DSurface9> surf3;
CComPtr<IDirect3DSurface9> surf4;
pDevice->GetRenderTarget( 0, surf0 ); // surface reference counter incremented, you should call Release() for this
surf1 = surf0; // surface reference count is not incremented, you shouldn't call Release() for this
pDevice->GetRenderTarget( 0, surf2 ); // surface reference counter incremented
CComPtr<IDirect3DSurface9> surf3 = surf0; // surface reference counter incremented
surf0->Release(); // release for pDevice->GetRenderTarget( 0, surf0 );
surf2.Release(); // .Release() used not ->Release() - it is important
surf4.Release(); // nothing happens because surf4 == 0
} // surf3.Release() is called in surf3 destructor
Also you may #define D3D_DEBUG_INFObefore including direct 3d headers and switch to debug d3d runtime. It is helpful in finding leaks in d3d app.
May the CComPtr Force be with you.
D3D objects are COM objects, and they use a basic reference counting system to manage the lifetime of the object. (See wikipedia for more info about the Component Object Model, or the MSDN article Managing Object Lifetimes)
The reference count is modified purely through the AddRef/Release methods, and certain other functions call those methods.
Creating the object as well as calling certain Get methods that return an object derived from the IUnknown class will call AddRef internally to increment the reference count, so you will need to call Release for each call when you are finished with the object.
If you pass the object to another function or class that stores a copy of the point (even temporarily) that class/function should call AddRef to ensure that the object is not freed while it is using it (and Release to signal it is done).
When the reference counter reaches 0 from a call to Release the object is signalled that it may be a good time to delete the held resources, but it may not happen immediately. There is also no protection for calling Release multiple times. The reference counter will not become negative, but it will not perform any other sanity checking (because it can't really) so you can cause application instability by trying to release references you don't hold.
Yes, you are correct. This is called reference counting and it ensures that objects are alive as long as they are being used, and no longer. You can use a variety of smart pointers to enforce this rule- both shared_ptr and (C++11) unique_ptr allow for custom deleters to call Release(). This makes it easy to control the lifetime of Direct3D objects just like you would for any other object in your application. You don't need to start including ATL libraries and CComPtr to use smart pointers with COM interfaces.