• Advertisement
Sign in to follow this  

[SOLVED] release() not working? (memory leaks...)

This topic is 3486 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

im using PIX to try and track down memory leaks in my program. Im down to the point where the only real resources i have left are the d3d9 object and device, some resources created by direct3d and d3dx... and then one other resource. Basically, every frame i'm creating a vertex buffer in a method. and at the start of this method, i release the buffer first. all works well till the end; after the end of my main game loop, i do another release of the object. However, it doesnt seem to get released; and then i look at the object viewer in the PIX experiment, and there is the object, still alive upon the end of execution. http://i38.tinypic.com/33m4r3a.png my release() call is exactly the same both in the method and after the end of the main loop... the vertexbuffer pointer is a global variable... also, its the final vertexbuffer to be used, but i used SetStreamSource with the null argument afterwards so it should be releasing. Or is there another thing i have to do to free up the buffer? i can show code if it helps. I'm not sure what to do about it at this point, but im sure its something common and newby since this is my first time cleaning up direct3d memory leaks. [Edited by - sqpat on August 3, 2008 8:08:53 PM]

Share this post


Link to post
Share on other sites
Advertisement
Quote:
i look at the object viewer in the PIX experiment, and there is the object, still alive

What do you mean by "still alive?" More importantly, what indication do you have that you have a memory leak?


[Edited by - Buckeye on August 2, 2008 10:40:27 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Buckeye
What do you mean by "still alive?" More importantly, what indication do you have that you have a memory leak?


I ran it with the debug runtime using the directx console and set breakpoints for memory leaks. One comes up upon the end of execution. Additionally, looking at what PIX is telling me, at the end of execution there are a couple of "live" pointers, i.e. they havent been deleted or released. That's how PIX defines if a memory region has been released or not; it's 'live', or 'dead'.

Quote:
Original post by Buckeye
Just because a memory pointer points to a recognizable object doesn't mean that object is useable. The memory pointed to may not be modified recognizably when the object is released. It may be written over later but, if PIX thinks it's a pointer to a vertex buffer and doesn't "know" it's released, it will faithfully interpret what it sees.


Well, the other stuff suggests that there is a memory leak, and the only other "live" pointers are the device/object pointers, and a couple that were created not by the application . i assume these would be released when the device/object stuff got released, which would get released when the vertex buffer got released.

Quote:
Original post by BuckeyeBy the way, a good programming practice is to set a pointer to NULL when you're done with it. First: initialize all your pointers to NULL. Then use a macro like the following to release your objects:
#define RELEASE(x) { if(x!=NULL) x->Release(); x=NULL; }



woo, thats pretty cool. thanks.

Share this post


Link to post
Share on other sites
How about posting the code, then, for the routine where you release and create the buffer?

Do you initialize all your DirectX pointers to NULL in some constructor or at the initialization of your app?

Share this post


Link to post
Share on other sites
here's my main function. a lot of my directx pointers are global vars.


int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreviousInstance,LPSTR lpcmdline,int nCmdShow){

srand( (unsigned)time(0) ); // should be done early

MSG msg_Message;

HWND han_Window = NewWindow("sqpat is awesome",100,100,640,480);
LPDIRECT3D9 p_dx_Object = Direct3DCreate9(D3D_SDK_VERSION);

LPDIRECT3DDEVICE9 p_Device = InitializeDevice(han_Window, p_dx_Object);

init_Sound(han_Window);

init_Char(han_Window, p_Device);

LPDIRECT3DVERTEXBUFFER9 p_dx_VB = init_Map(mapID, han_Window, p_Device);
LPDIRECT3DINDEXBUFFER9 p_dx_IB = FillIndices(han_Window, p_Device);
InitializeFont(han_Window, p_Device);
InitializeKeyboard(han_Window);
InitializeJoystick(han_Window);
SetupBackground(han_Window, p_Device);

OggPlayer op; // ogg player object
char musicName [40];
getMusicFilename(musicID, musicName);

op.InitDirectSound(han_Window);
op.OpenOgg(musicName); // oggplay startup
long tempInta = musicLoop;
op.Play(true, musicLoop); // oggplay with looping and loop point.

g_timer.StartTimer();

// START MAIN GAME LOOP

while(int_AppRunning){
if(PeekMessage(&msg_Message,han_Window,0,0,PM_REMOVE)){
DispatchMessage(&msg_Message);
}
if (!joystickFound) // If joystick not found
ReadKeyboard(inputKeyboard); // Read input from keyboard
else // else, (if joystick found)
ReadJoystick(inputJoystick, han_Window); // Read input from joystick

SetupBackground(han_Window, p_Device); // redraws bg for rotations
moveChars(); // Move characters and do physics crap
SetUpCamera(p_Device); // Adjust Camera
getSpriteFacing(); // Get Sprites' Camera-relative facing
updateAnimations(); // Get Sprites' Current frame.
DrawScene(p_Device, p_dx_VB, p_dx_IB, han_Window); // Output graphics display
maintainSound(); // Maintains SFX handling
if (op.IsPlaying()) // need this check in case you dont have looping and it stops
op.Update(); // Update ogg player
animateCounter++;
if (animated)
if (animateCounter == (animateNum * animateLength))
animateCounter = 0;
}

// END MAIN GAME LOOP


RELEASE(inputObject);
if (inputKeyboard != NULL){
inputKeyboard->Unacquire();
RELEASE(inputKeyboard);
}
if (inputJoystick != NULL){
inputJoystick->Unacquire();
RELEASE(inputJoystick);
}

RELEASE(p_dx_VB);
RELEASE(p_dx_IB);
RELEASE(p_dx_font);
RELEASE(myCyl);


for (int a = 0; a < numText; a++)
RELEASE(Texture[a]);
for (int a = 0; a < numChars; a++){
RELEASE(charSpriteFrames[a]);
}


DestroyWindow(han_Window);
delete [] charSpriteFrames;
delete [] charPos;
delete [] Texture;
delete [] textureMap;

sPerformance->Stop(NULL,NULL,0,0); //stop all playing music
RELEASE(sLoader); //release loader object

sPerformance->CloseDown(); //close down performance object
RELEASE(sPerformance); //release performance object
op.Close();
CoUninitialize(); //uninitialize COM


RELEASE(p_Device);
RELEASE(p_dx_Object);

return 0;
}





and heres where i create and release the vertex buffer



void SetupBackground(HWND han_Window, LPDIRECT3DDEVICE9 p_dx_Device){

OURCUSTOMVERTEX *cyl_Verts = new OURCUSTOMVERTEX[cylPrec*2];

if (myCyl != NULL)
RELEASE(myCyl);

float offset = (theta/(D3DX_PI));

for( int i=0; i<cylPrec; i++ ){
FLOAT cylTheta = (2*D3DX_PI*i)/(cylPrec-1)/2.0f;
cyl_Verts[2*i+0].y = -(extendMapValue*.8f) * sinf(cylTheta-theta+(D3DX_PI/2))+WIDTH/4;
cyl_Verts[2*i+0].x = (extendMapValue*.8f) * cosf(cylTheta-theta+(D3DX_PI/2))+HEIGHT/4;
cyl_Verts[2*i+0].z = 0;
cyl_Verts[2*i+0].color = 0xffffffff;
cyl_Verts[2*i+0].u = mapStretch * (offset - ((float)i)/(cylPrec-1));
cyl_Verts[2*i+0].v = 1.0f;
cyl_Verts[2*i+0].normal.x = (float)1;
cyl_Verts[2*i+0].normal.y = (float)1;
cyl_Verts[2*i+0].normal.z = (float)1;

cyl_Verts[2*i+1].y = -(extendMapValue*.8f) * sinf(cylTheta-theta+(D3DX_PI/2))+WIDTH/4;
cyl_Verts[2*i+1].x = (extendMapValue*.8f) * cosf(cylTheta-theta+(D3DX_PI/2))+HEIGHT/4;
cyl_Verts[2*i+1].z = 8.f;
cyl_Verts[2*i+1].color = 0xff808080;
cyl_Verts[2*i+1].u = mapStretch * (offset - ((float)i)/(cylPrec-1));
cyl_Verts[2*i+1].v = 0.0f;
cyl_Verts[2*i+1].normal.x = (float)1;
cyl_Verts[2*i+1].normal.y = (float)1;
cyl_Verts[2*i+1].normal.z = (float)1;
}

if (FAILED(p_dx_Device->CreateVertexBuffer(2*cylPrec*sizeof(OURCUSTOMVERTEX), D3DUSAGE_WRITEONLY , D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1, D3DPOOL_DEFAULT, &myCyl, NULL))){
MessageBox(han_Window,"Error while creating VertexBuffer","SetUpBackground()",MB_OK);
}

VOID* p_Vertices;
if (FAILED(myCyl->Lock(0, 2*cylPrec*sizeof(OURCUSTOMVERTEX), (void**)&p_Vertices, 0))){
MessageBox(han_Window,"Error trying to lock","SetUpBackground()",MB_OK);
}else{
memcpy(p_Vertices, cyl_Verts, 2*cylPrec*sizeof(OURCUSTOMVERTEX));
myCyl->Unlock();
}
delete [] cyl_Verts;
}






a lot of my directX data are global vars (not pretty, but i'll fix that later; i know its not whats causing the porblems)

anyways, how would i set the pointers to null on initialization? you mean something like

LPDIRECTINPUT8 inputObject;
&inputObject = NULL;

then make the inputObject?

Share this post


Link to post
Share on other sites
What I was suggesting is:

// initialization
LPDIRECT3DVERTEXBUFFER9 p_dx_VB = NULL;
LPDIRECT3DINDEXBUFFER9 p_dx_IB = NULL;
...
// in a loop somewhere
RELEASE(p_dx_VB);
RELEASE(p_dx_IB);
pDevice->CreateVertexBuffer(...,&p_dx_VB);
...
pDevice->CreateIndexBuffer(...,&p_dx_IB);
...


I'm not sure where myCyl enters the picture (it's not in the globals) but it might help to have something like:

// initialize
LPDIRECT3DVERTEXBUFFER9 myCyl = NULL;
...
void SetupBackground(...)
{
RELEASE(myCyl);
...
pDevice->CreateVertexBuffer(...,&myCyl);
...
}

With the RELEASE macro, you don't need "if(myCyl != NULL) RELEASE(myCyl);" as the macro includes "if(myCyl != NULL)". That assumes you initialize myCyl to NULL.

Also, it's good practice to clear the window inputs before you render.

while( app_running ) {
if( PeekMessage(..) ) {
// process message
} else { // do DirectX stuff only when messages are clear
// do DirectX stuff
}
}

Share this post


Link to post
Share on other sites
actually it was in my globals, being initialized to NULL as you just said. Meanwhile, the RELEASE(myCyl) and p_dx_Buffer->Create..(...&myCyl) are also already in SetupBackground, just near the start and end of the function.

(p_dx_VB and p_dx_IB are not being constantly remade, however)


I think i might just start stripping away code until i can get it running without a leak, then slowly add things to try and really pinpoint what I'm doing wrong.

Share this post


Link to post
Share on other sites
Quote:
actually it was in my globals

It's a little difficult to help diagnose code without seeing it! [wink]

Share this post


Link to post
Share on other sites
sorry about that. this is what it looks like right now

http://rafb.net/p/txHtF921.html


its pretty long.

Share this post


Link to post
Share on other sites
Still looking through the code, but noticed you "malloc" the Texture array and then "delete []" it. malloc should be paired with "free," not delete. Not sure what the effect of that is.

EDIT: you do the same with several variables. You should either "free(pointer)" or change the allocation to "new."

Share this post


Link to post
Share on other sites
hmm, i see. i just read up on free/delete/new/malloc. I had used C and Java but never C++ so im not sure on a couple of these quirks. You may have also noticed that I code this in a very C-like manner :P

So I changed the four delete[]s to:


free(charSpriteFrames);
free(charPos);
free(Texture);
free(textureMap);


it didnt seem to have any effect, but at least I'm doing things right now in that regard, thanks.

EDIT: I think the "new" instanced came from tutorials while i did the malloc ones (still using delete[]) on my own.

Share this post


Link to post
Share on other sites
The debug runtimes should tell you the allocation ID of the object that is still alive. Once you have that, you can set the runtime to break on allocation, and give it that ID. Then, when you run the program, it will break when the resource is allocated. After that, it's a simple matter of finding out why the resource isn't getting released.

Share this post


Link to post
Share on other sites
and i also ran back one of the ialloc IDs to this line on a breakpoint:



p_dx_font->DrawText(NULL, //pSprite
fps_string, //pString
-1, //Count
&font_rect, //pRect
DT_LEFT|DT_NOCLIP,//Format,
0xFFFFFFFF); //Color



i thought this was strange; the font itself is created elsewhere and only once, and similarly theres a release of it at the end. Could it be that one of those arguments creates a memory leak itself? Could DrawText be buggy?

EDIT: actually, a lot of things are coming back as memory leaks going backwards from the iallocid such as CreateTextureFromFile, DrawPrimitive, CreateVertexBuffer... but theyre mostly things that only come up once. From what i understand, these kinds of things can be locked up if theres some member of them that isnt released, so its my guess that there is a chain of dependencies that is resulting in a lot of leaks because of one thing at the end of a chain. The last thing in the chain seems to be the CreateVertexBuffer(...&myCyl) as i mentioned earlier. But of course, i'm no expert.

Share this post


Link to post
Share on other sites
Ok, let me try to explain some of what is happening a bit better because i know its hard to debug other people's code especially when it wont run for you.

the debug says there are 150 unfreed resources every time no matter how long i let it run. The first 146 of these are always the same, theyre near the start, have the same iallocIds, always trace back to the same lines of code. They happen for some lines of code that run only once.

The next four are two pairs of consecutive iallocIDs, and those two pairs always trace back to this statement:

    if (FAILED(p_dx_Device->CreateVertexBuffer(2*cylPrec*sizeof(OURCUSTOMVERTEX), D3DUSAGE_WRITEONLY , D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1, D3DPOOL_DEFAULT, &myCyl, NULL))){



the longer i run the program, the higher those last four unfreed resources' iallocIDs will be. which seems to support my thinking, and PIX's data, that the last creation of myCyl doesnt get freed up, but all the other previous ones do. I also am thinking that myCyl not being freed up is what makes the other (or the majority of) the other 146 resources unable to be released as well.

Ive done googling that suggests that there are some buggy directx functions that can tie up a vertex buffer if its the last one to be used, such as SetStreamSource, but I've even taken care to NULL those things.

hope that helps.



EDIT: So i did what i mentioned earlier, i stripped away parts of code and slowly found a problem here, a problem there. Some things probably were out of order, one or two things missing. Happy i can get back to coding again.

[Edited by - sqpat on August 3, 2008 8:46:28 PM]

Share this post


Link to post
Share on other sites
Why are you even recreating a vertex buffer per frame?

create it once, at the start of the application, and just refill and reuse it every frame. release it when the app closes.

Share this post


Link to post
Share on other sites
I like to reuse code. It's easier to do, faster to implement, looks cleaner, and is generally a good idea. Works just fine for me.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement