Sign in to follow this  
modex

MSDN samples (MEMORY LEAK)??

Recommended Posts

Hello All, I have a question in relation to the following link http://msdn.microsoft.com/en-us/library/dd371004(VS.85).aspx It compiles and runs fine no problems except when I follow the app using the Task manager and watch its memory, it counts Up continuously (only by about 2k every 4-5 seconds, more if you keep resizing the window) Most samples examples and tutorials I have seem also have this same effect! Is there something that can be done to prevent this?? Do all applications using DirectX OpenGL on the WIN32 platform do this? I can only assume its something todo with either the Callback procedure or message pump? Do "Professional" games/Programs use a different process for rendering etc as they dont seem to have this issue. I have tested this with just rendering the target view (d3d10) black, as a single page of code and encapsulated into classes with the same results (small memory leak) Am I doing something wrong? Any help greatly appreciated. [Edited by - modex on May 2, 2010 4:55:31 PM]

Share this post


Link to post
Share on other sites
I can't help much, all I can say is that my current win32 app has a pretty stable memory usage (shown in Task manager). It uses OpenGL, it's heavily based upon messages, so I don't think a constantly increasing memory usage (again: shown in Task manager) is normal.

Share this post


Link to post
Share on other sites
thanks szecs, I probably haven't explained my question very well. :( . . . I use visual studio 2010 rc . The win32 template works perfect (so i know its not the project config is ok) as soon as i setup directx for example and draw a simple triangle if its in a class or all on same page, put the function in the message loop compile the memory counts up. ↲↲I presume its looping the allocated resources and keeps adding them to the stack but if freed after the call then will the triangle not display or flicker on screen? ↲Or do i call the rendering function somewhere else? If i do why do all examples show otherwise(and seem to have memory leak) im really confused with this .

Share this post


Link to post
Share on other sites
First, the task manager is not a good way to be measuring memory usage. Stop that.

Second, you're asserting that you observe this problem in your own code when you initialize D3D. Why don't you post your code. You might be failing to release something.

Share this post


Link to post
Share on other sites
Thankyou for the replies, im not at my machine at the moment but will post the code in here later. the link in my first post presents the problem im describing, what should i be using to check my memory useage? I do apologise if i am frustrating anyone with my questions.

Share this post


Link to post
Share on other sites
It's not about frustration. It's just we can't help with no relevant info (code). It's pretty sure, that I won't dig into that MSDN-whatever (and I guess I'm not alone with that), but I would take a look at your code.

Share this post


Link to post
Share on other sites
At my machine now
The following code is using the class type way to setup app (using an adapted version of the WIN32 template

// Core_Graphics.cpp :
//
#pragma once


class Core_Graphics
{
public:
Core_Graphics();
virtual ~Core_Graphics();

virtual BOOL InitD3D();
virtual void ResizeD3D10Window(int width, int height);
virtual BOOL GoDemo();
virtual void Update();

virtual void Render();

virtual void CleanUP();


ID3D10Device *g_d3dDevice;
IDXGISwapChain *g_swapChain;
ID3D10RenderTargetView *g_renderTargetView;
HWND m_hWnd;


};








// Core_Graphics.cpp :
//
#include "StdAfx.h"
#include "Core_Graphics.h"


Core_Graphics::Core_Graphics()
{
}


Core_Graphics::~Core_Graphics()
{
CleanUP();
}


BOOL Core_Graphics::InitD3D()
{
DXGI_SWAP_CHAIN_DESC swapDesc;

ZeroMemory(&swapDesc, sizeof(swapDesc));

swapDesc.BufferCount = 2;
swapDesc.BufferDesc.Width = 800;
swapDesc.BufferDesc.Height = 600;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = m_hWnd;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.Windowed = TRUE;

HRESULT hr;
unsigned int flags =0;

#ifdef _DEBUG
flags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_NULL;

D3D10_DRIVER_TYPE driverTypes[] =
{
D3D10_DRIVER_TYPE_HARDWARE,
D3D10_DRIVER_TYPE_REFERENCE,
};




unsigned int numDriverTypes = sizeof(driverTypes) /
sizeof(driverTypes[0]);


for(unsigned int i = 0; i < numDriverTypes; i++)
{
driverType = driverTypes[i];

hr = D3D10CreateDeviceAndSwapChain(NULL, driverType, NULL, flags,
D3D10_SDK_VERSION, &swapDesc, &g_swapChain, &g_d3dDevice);

if(SUCCEEDED(hr))
break;
}


if(FAILED(hr))
return FALSE;


ID3D10Texture2D *buffer = NULL;
hr = g_swapChain->GetBuffer(0,__uuidof(ID3D10Texture2D),(LPVOID*)&buffer);

if(FAILED(hr))
return FALSE;

hr = g_d3dDevice->CreateRenderTargetView(buffer, NULL, &g_renderTargetView);

buffer->Release();


if(FAILED(hr))
return FALSE;




g_d3dDevice->OMSetRenderTargets(1, &g_renderTargetView, NULL);

ResizeD3D10Window(800,600);

return TRUE;

}





void Core_Graphics::ResizeD3D10Window(int width, int height)
{
if(g_d3dDevice == NULL)
return;

D3D10_VIEWPORT vp;

vp.Height = height;
vp.MaxDepth = 1.0f;
vp.MinDepth = 0.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = width;

g_d3dDevice->RSSetViewports(1,&vp);

}

BOOL Core_Graphics::GoDemo()
{
return TRUE;
}

void Core_Graphics::Update()
{
}



void Core_Graphics::Render()
{
float col[4] = {1,0,0,1};

g_d3dDevice->ClearRenderTargetView(g_renderTargetView, col);

g_swapChain->Present(0,0);

}

void Core_Graphics::CleanUP()
{
if(g_d3dDevice) g_d3dDevice->ClearState();
if(g_swapChain) g_swapChain->Release();
if(g_renderTargetView) g_renderTargetView->Release();

if(g_d3dDevice) g_d3dDevice->Release();
}







// D3D_App.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "D3D_App.h"

#define MAX_LOADSTRING 100
Core_Graphics Graphics;
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_D3D_APP, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_D3D_APP));
if(Graphics.InitD3D() == true)
{
if(Graphics.GoDemo() == true)
{
while(1)
{


// Main message loop:
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;

TranslateMessage(&msg);
DispatchMessage(&msg);

}else{

Graphics.Update();
Graphics.Render();
}



}
}

}


return (int) msg.wParam;
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_D3D_APP));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_D3D_APP);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
Graphics.m_hWnd = hWnd; //not the best way I realise but been trying different things
if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);


return TRUE;
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:


case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
// Graphics.Update(); <---tried moving from message loop to here
//Graphics.Render();
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}












Next is the tutorial code from a book



/*
Chapter 2 - Blank Window
Ultimate Game Programming with DirectX 2nd Edition
Created by Allen Sherrod
*/


#include<windows.h>
#include<d3d10.h>
#include<d3dx10.h>

#pragma comment(lib, "d3d10.lib")
#pragma comment(lib, "d3dx10.lib")

#define WINDOW_NAME "Blank Window"
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600


// Direct3D 10 objects.
ID3D10Device *g_d3dDevice = NULL;
IDXGISwapChain *g_swapChain = NULL;
ID3D10RenderTargetView *g_renderTargetView = NULL;


bool InitializeDemo()
{
// Nothing to initialize.

return true;
}


void Update()
{
// Nothing to update.
}


void RenderScene()
{
float col[4] = { 1, 0, 0, 1 };

// Clear the rendering destination to a specified color.

g_d3dDevice->ClearRenderTargetView(g_renderTargetView, col);

// Display the results to the target window (swap chain).

g_swapChain->Present(0, 0);
}


void Shutdown()
{
// Release all used memory.

if(g_d3dDevice) g_d3dDevice->ClearState();
if(g_swapChain) g_swapChain->Release();
if(g_renderTargetView) g_renderTargetView->Release();

if(g_d3dDevice) g_d3dDevice->Release();
}


void ResizeD3D10Window(int width, int height)
{
if(g_d3dDevice == NULL)
return;

D3D10_VIEWPORT vp;

vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;

g_d3dDevice->RSSetViewports(1, &vp);
}


bool InitializeD3D10(HWND hwnd)
{
DXGI_SWAP_CHAIN_DESC swapDesc;
ZeroMemory(&swapDesc, sizeof(swapDesc));

// A swap chain needs to be created first. Once created
// we can create a rendering target that can allow us to
// actually draw to the swap chain (the window).

swapDesc.BufferCount = 2;
swapDesc.BufferDesc.Width = WINDOW_WIDTH;
swapDesc.BufferDesc.Height = WINDOW_HEIGHT;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = hwnd;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.Windowed = TRUE;

HRESULT hr = S_OK;
unsigned int flags = 0;

// This next flag gives us debug information
// during development. Not used in release versions.

#ifdef _DEBUG
flags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_NULL;

D3D10_DRIVER_TYPE driverTypes[] =
{
D3D10_DRIVER_TYPE_HARDWARE,
D3D10_DRIVER_TYPE_REFERENCE,
};

// Loop through each device type and see if we can create
// at least one of them. If they all fail then there is
// a huge problem with your hardware or DirectX
// installation.

unsigned int numDriverTypes = sizeof(driverTypes) /
sizeof(driverTypes[0]);

for(unsigned int i = 0; i < numDriverTypes; i++)
{
driverType = driverTypes[i];

hr = D3D10CreateDeviceAndSwapChain(NULL, driverType, NULL,
flags, D3D10_SDK_VERSION,
&swapDesc, &g_swapChain,
&g_d3dDevice);
if(SUCCEEDED(hr))
break;
}

if(FAILED(hr))
return false;

// Get the back buffer from the rendering swap chain so we
// can create a destination rendering target from it.

ID3D10Texture2D *buffer = NULL;
hr = g_swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D),
(LPVOID*)&buffer);

// Check for problems creating the previous object.

if(FAILED(hr))
return false;

// Create the default render destination for the drawing calls.

hr = g_d3dDevice->CreateRenderTargetView(buffer, NULL,
&g_renderTargetView);

// No longer need this once the render target viw is created.

buffer->Release();

// Check for problems creating the previous object.

if(FAILED(hr))
return false;

// Set default render target. Can be set during the rendering
// but since there is only 1 render target it can be set once.

g_d3dDevice->OMSetRenderTargets(1, &g_renderTargetView, NULL);

// Ensure window is ready to be drawn to.

ResizeD3D10Window(WINDOW_WIDTH, WINDOW_HEIGHT);

return true;
}


// *** WIN32 STUFF FROM HERE ON ***


LRESULT CALLBACK WndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp)
{
// Window width and height.
int width, height;

switch(m)
{
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;

case WM_SIZE:
height = HIWORD(lp);
width = LOWORD(lp);
if(height == 0)
height = 1;

ResizeD3D10Window(width, height);
return 0;
break;

case WM_KEYDOWN:
switch(wp)
{
case VK_ESCAPE:
PostQuitMessage(0);
break;

default:
break;
}
break;

default:
break;
}

// Pass remaining messages to default handler.
return (DefWindowProc(hwnd, m, wp, lp));
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmd, int show)
{
MSG msg;

// Describes a window.
WNDCLASSEX windowClass;
memset(&windowClass, 0, sizeof(WNDCLASSEX));
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.lpszClassName = "DX10CLASS";
windowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&windowClass))
return 0;

// Create the window.
HWND hwnd = CreateWindowEx(NULL, "DX10CLASS", WINDOW_NAME,
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 100, 100,
WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, hInstance, NULL);

if(!hwnd)
return 0;

ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);

// If initialize fail don't run the program.
if(InitializeD3D10(hwnd) == true)
{
if(InitializeDemo() == true)
{
// This is the messsage loop.
while(1)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
// If a quit message then break;
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Update();
RenderScene();
}
}
}
}

// Release all resources and unregister class.
Shutdown();
UnregisterClass("DX10CLASS", windowClass.hInstance);

return (int)msg.wParam;
}






Both ways give me the same increasing memory (measured by tak manager) If i leave the compiled app running it appears to blink (look as if its closing and restarting) in the task bar and memory counts up. Memory will get higher if resized or mouse is clicked or moved around the window when the application is active.




Share this post


Link to post
Share on other sites
I cannot notice anything spectacular in the code at first glance, but one thing:
You handle WM_PAINT but you have a render explicitly in the game loop too. The second code you posted (and my codes too) doesn't have that.

Plus you have a WM_COMMAND before WM_PAINT without a break, so every WM_COMMANDs will 'leak' onto the WM_PAINT.

Remove those messages altogether, and see what happens.

Sidenote: I use openGL, whee you don't have to handle WM_PAINT if you don't want to. Maybe it's different in DirectX, but anyway, that "leaking" WM_COMMAND is a bug.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this