Irrlicht 1.8. Application not closing and memory leak...

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by REDDemon »

It does not initialize to zero because it is duplicated (at least that's the same Issue I had), the variable you see, is not the same in the DLL:

do that---> having all inside .cpp grants to modify only 1 variable.

Code: Select all

 
namespace irr
{
 
///BAD SHOULD BE INTO CReferenceCounted.cpp
s32 IReferenceCounted::GlobalRefCounter = 0; // static variables should be iniziatilized this way.  syntax was decided to be this.
 
void IReferenceCounted::IncreaseGlobalCount() //move this to cpp file
{
    IReferenceCounted::GlobalRefCounter++;
}
 
bool IReferenceCounted::decreaseGlobalCount() //move this to cpp file
{
    IReferenceCounted::GlobalRefCounter--;
}
 
s32 IReferenceCounted::getGlobalCount() //move this to cpp file
{
    return IReferenceCounted::GlobalRefCounter;
}
///OLD GOOD IRRLICHT CODE.
 
//! stub for calling createDeviceEx
IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice(video::E_DRIVER_TYPE driverType,
 
Anyway there's still the issue of constructor called twice with ceratin classes. ^^ And that's a big problem for global counting. Usually constructor should be called only once.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

Okay, I´ve debugged it and it is working, just didn´t expect to get a global counter of 143 straight after createDeviceEx!

Using the leak demo, code as below, after createDeviceEx driver counter is 8, and global 143.

After setting up the scene, driver same, global increases to 159.

After running the begin-end scene loop, global increased to 165.

After removeAllTextures global reduces to 158.

So just before the device drop call, the driver has 8 counts, and globally there are 158.

During the device drop operation the global count is reduced to 8, with no further calls to drop.

... a small leak?

Code: Select all

 
/** Modified Irrlich Example 014 Win32 Window
 
Leak tester Mk1:
 
*** This sample can be used to cycle test the Irrlich engine to look for driver or engine memory leaks ***
 
For Windows 7, 8 or XP.
Compiled and tested on Windows 7 64-bit, with VS 2010, 32-bit output, in debug mode.
 
NOTE!!!  Testing this now with 1.8, a memory leak occurs when the flag to create scene content, bCreateScene, is set to false!
 
Why should a massive leak occur just because there is no scene content?
 
Robmar 15/11/2012
***
This example only runs under MS Windows and demonstrates that Irrlicht can
render inside a win32 window. MFC and .NET Windows.Forms windows are possible,
too.
 
In the beginning, we create a windows window using the windows API. I'm not
going to explain this code, because it is windows specific. See the MSDN or a
windows book for details.
*/
 
#include <irrlicht.h>
#ifndef _IRR_WINDOWS_
#error Windows only example
#else
#include <windows.h> // this example only runs with windows
#include <iostream>
#include "driverChoice.h"
 
using namespace irr;
 
#pragma comment(lib, "irrlicht.lib")
 
HWND hOKButton;
HWND hWnd;
 
static LRESULT CALLBACK CustomWndProc(HWND hWnd, UINT message,
        WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            HWND hwndCtl = (HWND)lParam;
            int code = HIWORD(wParam);
 
            if (hwndCtl == hOKButton)
            {
                DestroyWindow(hWnd);
                PostQuitMessage(0);
                return 0;
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
 
    }
 
    return DefWindowProc(hWnd, message, wParam, lParam);
}
 
 
/*
   Now ask for the driver and create the Windows specific window.
*/
int main()
{
    // ask user for driver
    video::E_DRIVER_TYPE driverType=driverChoiceConsole();
    if (driverType==video::EDT_COUNT)
        return 1;
 
    printf("Select the render window (some dead window may exist too):\n"\
        " (a) Window with button (via CreationParam)\n"\
        " (b) Window with button (via beginScene)\n"\
        " (c) Own Irrlicht window (default behavior)\n"\
        " (otherKey) exit\n\n");
 
    char key;
    std::cin >> key;
    if (key != 'a' && key != 'b' && key != 'c')
        return 1;
 
    HINSTANCE hInstance = 0;
    // create dialog
 
    const char* Win32ClassName = "CIrrlichtWindowsTestDialog";
 
    WNDCLASSEX wcex;
    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)CustomWndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = DLGWINDOWEXTRA;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW);
    wcex.lpszMenuName   = 0;
    wcex.lpszClassName  = Win32ClassName;
    wcex.hIconSm        = 0;
 
    RegisterClassEx(&wcex);
 
    DWORD style = WS_SYSMENU | WS_BORDER | WS_CAPTION |
        WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX;
 
    int windowWidth = 800;
    int windowHeight = 600;
 
    hWnd = CreateWindow( Win32ClassName, "Irrlicht Win32 Leak Test",
        style, 100, 100, windowWidth, windowHeight,
        NULL, NULL, hInstance, NULL);
 
    RECT clientRect;
    GetClientRect(hWnd, &clientRect);
    windowWidth = clientRect.right;
    windowHeight = clientRect.bottom;
 
    // create ok button
 
    hOKButton = CreateWindow("BUTTON", "OK - Close", WS_CHILD | WS_VISIBLE | BS_TEXT,
        windowWidth - 160, windowHeight - 40, 150, 30, hWnd, NULL, hInstance, NULL);
 
    // create some text
 
    CreateWindow("STATIC", "This is Irrlicht running inside a standard Win32 window.\n"\
        "Also mixing with MFC and .NET Windows.Forms is possible.",
        WS_CHILD | WS_VISIBLE, 20, 20, 400, 40, hWnd, NULL, hInstance, NULL);
 
    // create window to put irrlicht in
 
    HWND hIrrlichtWindow = NULL;
    //hIrrlichtWindow = CreateWindow("BUTTON", "",
    //      WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
    //      50, 80, 320, 220, hWnd, NULL, hInstance, NULL);
    video::SExposedVideoData videodata((key=='b')?hIrrlichtWindow:0);
 
    // show and execute dialog
 
    ShowWindow(hWnd , SW_SHOW);
    UpdateWindow(hWnd);
 
    /*
    So now that we have some window, we can create an Irrlicht device
    inside of it. We use Irrlicht createEx() function for this. We only
    need the handle (HWND) to that window, set it as windowsID parameter
    and start up the engine as usual. That's it.
    */
    // create irrlicht device in the button window
 
    irr::IrrlichtDevice *device;
    irr::video::IVideoDriver * pDriver;
    irr::scene::ISceneManager * pSmgr;
    irr::SIrrlichtCreationParameters *pParam;
 
    irr::video::SColor sc;
    sc.set( 0xff, 0, 0, 0x32 );
  
    // do message queue
 
    /*
    Now the only thing missing is the drawing loop using
    IrrlichtDevice::run(). We do this as usual. But instead of this, there
    is another possibility: You can also simply use your own message loop
    using GetMessage, DispatchMessage and whatever. Calling
    Device->run() will cause Irrlicht to dispatch messages internally too.
    You need not call Device->run() if you want to do your own message
    dispatching loop, but Irrlicht will not be able to fetch user input
    then and you have to do it on your own using the window messages,
    DirectInput, or whatever.
    */
 
    MSG msg;
    while (true)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
 
            if (msg.message == WM_QUIT)
                break;
        }
 
        bool bCreateScene = 1;
 
        while ( 1 )
        {
            int iLoopCycle = 50;                // Max loop count
 
            //std::cin >> key;          // Run loop un key stroke to monitor resource use step by step
            //if ( key == 'x' && key == 'X' )
            //  return 1;
 
            pParam = new irr::SIrrlichtCreationParameters;
 
            pParam->DriverType = driverType;
            if (key=='a')
                pParam->WindowId = reinterpret_cast<void*>(hIrrlichtWindow);
 
            pParam->AntiAlias = irr::video::EAAM_LINE_SMOOTH;    // 4
            pParam->WindowId = reinterpret_cast<void*>(hWnd);    // From external CWnd (important as OpenFL driver seems to have a problem when using ext windows)
 
            video::SExposedVideoData videodata( hWnd );       // Structure for holding data describing driver and operating system specific data
 
            pParam->DeviceType = EIDT_WIN32;
            pParam->DriverType = video::EDT_OPENGL;       // EDT_DIRECT3D9 EDT_DIRECT3D8 EDT_OPENGL
            //pParam->DriverType = video::EDT_DIRECT3D9;      // EDT_DIRECT3D8 EDT_OPENGL
            pParam->Stencilbuffer = true;     // Needed for shadows
            pParam->Bits = 32;
            pParam->Doublebuffer = true;     // To avoid drawing artifacts
            pParam->Vsync = true;               // If set false, shearing may occur
 
            //pParam->Vsync = true;             // If set false, shearing may occur
            pParam->EventReceiver = NULL;
            //pParam->EventReceiver = &receiver;   // Crashes logger in debug mode with MFC ex Wnd, and otherwise doesn't work from separate thread!
 
            pParam->WindowSize = core::dimension2d<u32>( 1024, 768 );
 
            pParam->HighPrecisionFPU = true;   // MUST BE SET TO AVOID MATHS FAILURES EN COLEDATETIME AND POSSIBLY OTHER MS/MFC FUNCTIONS
            pParam->WithAlphaChannel = true;
 
            device = irr::createDeviceEx( *pParam );    // Create 3D engine
            if (!device)
                return 1;
 
            // Get drivers
            pDriver = device->getVideoDriver();
            pSmgr = device->getSceneManager();
 
            irr::s32 GlobRefCount1 = pDriver->getGlobalReferenceCount();
            int iDRC = pDriver->getReferenceCount();
 
            if ( driverType == video::EDT_OPENGL )
            {
                // SO WHY IS THIS CODE NEEDED?  -  wglShareLists : Enables multiple OpenGL rendering contexts to share a single display-list space
                HDC HDc=GetDC(hIrrlichtWindow);
                PIXELFORMATDESCRIPTOR pfd={0};
                pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
                int pf = GetPixelFormat(HDc);
                DescribePixelFormat(HDc, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
                pfd.dwFlags |= PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
                pfd.cDepthBits=16;
                pf = ChoosePixelFormat(HDc, &pfd);
                SetPixelFormat(HDc, pf, &pfd);
                videodata.OpenGLWin32.HDc = HDc;
                videodata.OpenGLWin32.HRc=wglCreateContext(HDc);
                wglShareLists((HGLRC)pDriver->getExposedVideoData().OpenGLWin32.HRc, (HGLRC)videodata.OpenGLWin32.HRc);
            }
 
            device->setResizable( true );      // Window is resizeable
            pDriver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, TRUE);
            pDriver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, TRUE);
            pDriver->setTextureCreationFlag(video::ETCF_NO_ALPHA_CHANNEL, FALSE);    // Use alpha
            if ( !pDriver->queryFeature( video::EVDF_TEXTURE_NPOT ) )        // If non power-2 supported, allow // NOTE: ALWAYS ADJUST TO REDUCE CPU OVERHEAD
                pDriver->setTextureCreationFlag( video::ETCF_ALLOW_NON_POWER_2 );
 
            // advance virtual time
            device->getTimer()->tick();
 
            if ( bCreateScene )
            {
                scene::ICameraSceneNode* cam = pSmgr->addCameraSceneNode();
                cam->setTarget(core::vector3df(0,0,0));
 
                scene::ISceneNodeAnimator* anim =
                pSmgr->createFlyCircleAnimator(core::vector3df(0,15,0), 30.0f);
                cam->addAnimator(anim);
                anim->drop();
 
                scene::ISceneNode* cube = pSmgr->addCubeSceneNode(20);
 
                cube->setMaterialTexture(0, pDriver->getTexture("../../media/wall.bmp"));
                cube->setMaterialTexture(1, pDriver->getTexture("../../media/water.jpg"));
                cube->setMaterialFlag( video::EMF_LIGHTING, false );
                cube->setMaterialType( video::EMT_REFLECTION_2_LAYER );
            }
 
            irr::s32 GlobRefCount2 = pDriver->getGlobalReferenceCount();
            int iDRC2 = pDriver->getReferenceCount();
 
            while ( device->run() &&  iLoopCycle-- )
            {
                pDriver->beginScene( true, true, sc );  // Call before rendering, clear screen
//              pDriver->beginScene( true, true, sc, videodata );  // Call before rendering, clear screen
                pSmgr->drawAll();
                pDriver->endScene(); // The updated (engine animations only) screen frame now gets presented
 
                Sleep( 1000/50 );       // Maintain cycle rate independent of content loading
            }
 
            irr::s32 GlobRefCount3 = pDriver->getGlobalReferenceCount();
            int iDRC3 = pDriver->getReferenceCount();
 
            pDriver->removeAllTextures();
 
            irr::s32 GlobRefCount4 = pDriver->getGlobalReferenceCount();
            int iDRC4 = pDriver->getReferenceCount();
 
            device->closeDevice();
            device->run();
 
            irr::s32 GlobRefCount5 = pDriver->getGlobalReferenceCount();
            int iDRC5 = pDriver->getReferenceCount();
 
            device->drop();
 
            if ( pParam )
                delete pParam;   // Delete and recreate on each loop
        }
    }
 
    return 0;
}
#endif // if windows
 
/*
That's it, Irrlicht now runs in your own windows window.
**/
 
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

I changed the destructer as below, and CColladerFileLoader and CVideoModeList never call drop, although grab was called.

Code: Select all

 
        //! Destructor.
        virtual ~IReferenceCounted()
        {
            _IRR_DEBUG_BREAK_IF(ReferenceCounter > 0)       // Check if deleted without calling drop, which leaves global counter incorrect
        }
 
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

Seems that there are lots of classes, such as SDummyTexture, that use IReferenceCounted, and with the code example for a global reference counter, will always leave it incremented, as drop is never called.

So the code example given for a global ref counter won´t give correct results.

Maybe by taking the increment of the global counter out of the class, and just counting grabs would be more meaningful???
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by CuteAlien »

Use a static array instead of a reference counter. Add objects into it in the constructor and remove them from the array when the reference counted object is deleted. Then you should have at the end an array which contains all objects left over and can simply look at them with the debugger.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

If we assume that the destructor of all classes deletes all allocations, then that might work. But what if a class calls malloc? The class can get deleted and still leak resources.

That´s a goo idea about the array, any objects not deleted would have a pointer in the array, but it would have to be void pointer, so maybe we´d need an array element also to store the class identifier.

This needs a little thought...
Last edited by robmar on Sun Dec 09, 2012 9:01 am, edited 1 time in total.
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

I´ve modified the destructor as below, and the global count now reduces to 14 in my MFC app using D3D and OpenGL drivers, but no further, and this on only creating and destroying the engine.

Any ideas on code to store an array of useful class info along with each ref?

Code: Select all

        //! Destructor.
        virtual ~IReferenceCounted()
        {
            if ( ReferenceCounter > 0 )
                --GlobalRefCounter;
 
            _IRR_DEBUG_BREAK_IF( ReferenceCounter > 1 )     // Check if deleted and grabs still existing
        }
 
 
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by CuteAlien »

The idea is about counting reference counted objects easier. For object allocated using other mechanisms this certainly won't work (you need other tools for that).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

Yes that´s what I was thinking.

So what do you think of the destructor changes, does that seem correct?

I also added a final call in CNullDriver´s destructor to get the final global count, and with both drivers and no scene loaded, it end at 14 counts.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by hybrid »

robmar wrote:I changed the destructer as below, and CColladerFileLoader and CVideoModeList never call drop, although grab was called.

Code: Select all

 
        //! Destructor.
        virtual ~IReferenceCounted()
        {
            _IRR_DEBUG_BREAK_IF(ReferenceCounter > 0)       // Check if deleted without calling drop, which leaves global counter incorrect
        }
 
This cannot be the case. CColladaFileLoader is stored in a central array in the scene manager, which is completely dropped and emptied on destruction of the scene manager. The VideoModeList is in deed a bug, though, as it is an IReferenceCounted object, but is used as a statically allocated member. This won't be a problem, though, as the member is deletd anyway, so no leak here and no prevention of further removal.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by CuteAlien »

Sorry, I don't really have the time right now to dig into this (working on another software release right now in my job). I'll take a look when I find time again (maybe next weekend or so).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

Okay, I´ll check the OpenGL context release code to see if I can find the leak that occurs at window destruction, will post if I find anyting.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by hybrid »

I've found another statically allocated member of type IReferenceCounted, the attributes in SceneManager. Now my global reference counter is down to three after dropping the device.
robmar
Posts: 1125
Joined: Sun Aug 14, 2011 11:30 pm

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by robmar »

Can you give a file and line number list of these locations?

I changed the drop function to speed up the deletion:-

if (ReferenceCounter==1)
{
delete this;
return true;
}
ReferenceCounter--;
GlobalReferenceCounter--;

In the destructor, I also only decrement the global counter if the ReferenceCounter is > 1. This solved a problem with mismatches between counters caused by class creation and drop not being called before destruction.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Irrlicht 1.8. Application not closing and memory leak...

Post by hybrid »

Changes are here:
http://irrlicht.svn.sourceforge.net/vie ... ision=4385
Your change would leave the global ref counter out of sync by one for each destruction though, and test against 1 is probably not always using a constant 1 register, which means that we have a load here, a store there, but maybe not worth the hassle.
Post Reply