Releasing memory from OpenGL

I have an application that makes a beautiful solid model with OpenGL. When I close the window, the memory is not released. There must be a simple function call that will close everything and release it – but I cannot find it. Do I have to do a glDeleteBuffers(…) for everything individually? After many windows are opened and closed, the application crashes, likely because of the memory limit.

Destroying the context owning the buffer (or all contexts owning a buffer for shared contexts) should destroy the buffer. Likewise for textures.

The only things I create are two call lists:

	glCallList(m_OGLraylistName);
	glCallList(m_OGLlistName);

Each of these has many data items. When I close the window, I delete them:

	glDeleteLists( m_OGLlistName,1 );
	glDeleteLists( m_OGLraylistName,1 );

How does one destroy the context? I know very little about OpenGL. Can you give me an example?

Running my program in Debug mode, the Task Manager says I’m using 9.3 MB. When I display the OpenGL window, it says 74.4 MB. When I close the window, it says 65.0. So something is still hogging lots of memory.

You would have to have much more initiation-code to present something on the screen. I’m not very proficient on old style opengl. Popping a default old-style opengl project on my windows-pc ends the program with

void DisableOpenGL (HWND hwnd, HDC hDC, HGLRC hRC)
{
    wglMakeCurrent(NULL, NULL);
    wglDeleteContext(hRC);
    ReleaseDC(hwnd, hDC);
}

Maybe you can tell us about the platform you use or more on how you make something appear on the screen in the first place.
What about the data you display? I would come from a file that could be open still?

Certainly. Here’s how I create the window:

BOOL CmyOGLView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
	if (A.JDATSW[106] == 1) wndout("Create\r\n");

	m_matrix[0] = 0.0;
	m_matrix[1] = 0.0;
	m_matrix[2] = 0.0;
	m_matrix[3] = 0.0;
	m_matrix[4] = 0.0;
	m_matrix[5] = 0.0;
	m_matrix[6] = 0.0;
	m_matrix[7] = 0.0;
	m_matrix[8] = 0.0;
	m_matrix[9] = 0.0;
	m_matrix[10] = 0.0;
	m_matrix[11] = 0.0;
	m_matrix[12] = 0.0;
	m_matrix[13] = 0.0;
	m_matrix[14] = 0.0;
	m_matrix[15] = 0.0;

	m_rotX = m_matrix[0];
	m_rotY = m_matrix[4];
	m_rotZ = m_matrix[8];

	float tint = 1.0;
	m_clearColor[0] = tint;		// red
	m_clearColor[1] = tint;		// green
	m_clearColor[2] = tint;		// blue
	m_clearColor[3] = tint;		// alpha (says the book; but it must = tint to work!)

// local variables  
    HDC      hDC ;
    HGLRC    hglrc ;
 
    // obtain a device context for the window  
    hDC = ::GetDC(m_hWnd); 
    OGLhDC = hDC;

	m_myParent = pParentWnd;
	return CScrollView::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}

And here is how it is initialized:

void CmyOGLView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
		if (A.JDATSW[106] == 1) wndout("OnInitialUpdate \r\n");

	asmfixerror();
	oglbugcount = 0;

	CSize sizeTotal;
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);

	GetWindowRect( &m_OGLarea );
	ScreenToClient( &m_OGLarea );
	float aspect = float( m_OGLarea.right - m_OGLarea.left )/float(m_OGLarea.bottom - m_OGLarea.top );
	glMatrixMode( GL_MODELVIEW );	
	glLoadIdentity();
	GLdouble left = -5.5;
	GLdouble right = 5.5;
	GLdouble bottom = -5.5/aspect;
	GLdouble top = 5.5/aspect;
	GLdouble zNear = -10.0;
	GLdouble zFar = 10.0;
	glOrtho( left, right, bottom, top, zNear, zFar );
	m_red = 1.0;
	m_green = 1.0;
	m_blue = 1.0;
	m_w = 1;
	m_isLdragging = false;
	m_isRdragging = false;
	m_isZooming = false;
	m_FangleRot = 90.0;	// degrees; click on arrow buttons does this
	m_dialogScale = 1.0;
	m_oldCx = 0;
	m_lastMouseX = 0;
	m_lastMouseY = 0;
	m_zoomfactor = 1;
	m_blackonwhite = GRBLACKONWHITE;

	CClientDC ClientDC (this);	
	HDC hDC = ClientDC.m_hDC;
	myOGLView = this;
	LastClicked = this;
	glFinish();

	int nPixelFormat;

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof( PIXELFORMATDESCRIPTOR ),
		1,
		PFD_DRAW_TO_WINDOW |
		PFD_SUPPORT_OPENGL |
		PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,		// PixelType
		32,					// ColorBits
//		16,					// ColorBits
		0,0,				// RedBits, Redshift
		0,0,0,0,			// G, B
		0,0,				// AlphaBits, Shift
		0,0,0,0,0,			// AccumBits, R, G, B, A
		16,					// DepthBits
		0,					// StencilBits
		0,					// AuxBuffers
		0,					// iLayerType
		0,					// Reserved
		0,0,0				// LayerMask, VisMask, DamageMask
	};

	nPixelFormat = ChoosePixelFormat( hDC, &pfd);
	SetPixelFormat( hDC, nPixelFormat, &pfd );

	hRC = wglCreateContext( hDC );
	wglMakeCurrent( hDC, hRC );	
	glEnable( GL_DEPTH_TEST );

	RECT rec;
	int cx,cy;
	AfxGetMainWnd()->GetClientRect( &rec );

	int size = rec.right - rec.left;	// width of screen

	int tileX,tileY,tilenrows,thistile,tilepointx,tilepointy,indexY,indexX;
	float tileSpace,xf;

	thistile = A.ISFLAGS[252];		// index, this picture

	if ( thistile > 0 ) {		// TILE in effect
		tileSpace = size*A.SFLAGS[214]*0.191;	// spacing, pixels
		tileX = size*A.SFLAGS[217];				// start, X, pixels
		tileY = size*A.SFLAGS[218];				// start, Y, pixels
		tilenrows = A.ISFLAGS[253];				// grid number in X
		indexY = (thistile - 1)/tilenrows;		// row, this picture
		indexX = thistile - tilenrows*indexY ;	// column, this picture

		xf = 100.0;
		tilepointy = tileY + indexY*(tileSpace + xf)*A.SFLAGS[216];		// row location; leave room for frame and toolbar

		xf = (15.0 + 0.02645*tileSpace);
		tilepointx = tileX + (indexX - 1)*(tileSpace + xf)*A.SFLAGS[216];	// column

		rec.top = tilepointy;
		rec.left = tilepointx;
		rec.right = rec.left + tileSpace*1.1;
		rec.bottom = rec.top + tileSpace*1.3;
		A.ISFLAGS[252]++;			// ready next

	} else {

		cx = 500 + (rec.right - rec.left)/2;
		rec.top = 0;
		rec.bottom = 640;
		rec.left = cx - 593;	// so circles come out round
		rec.right = cx;
	}
	m_myParent->MoveWindow( &rec );	// set initial position of window
}

The actual data for the display are generated by Fortran programs that feed routines to OpenGL. Here is an example:

void CmyOGLView::OGLaddPolyStrip(float x, float y, float z)
{
		if (A.JDATSW[106] == 1) wndout("OGLaddPolyStrip\r\n");
	m_vertexCount += 1;
	glEdgeFlag( TRUE );

	if ( m_vertexCount == 1 ) {			// 1st vertex, new panel
		m_x1 = x;
		m_y1 = y;
		m_z1 = z;

	} else if ( m_vertexCount == 2 ) {
		m_x2 = x;
		m_y2 = y;
		m_z2 = z;

	} else if ( m_vertexCount == 3 ) {	// 2nd vertex
		m_x3 = x;
		m_y3 = y;
		m_z3 = z;		
		
	} else if ( m_vertexCount == 4 ) {	// need surface normals		
		m_x4 = x;
		m_y4 = y;
		m_z4 = z;

		findNormal();					// from 2, 3, 4

		glNormal3f( m_normalx, m_normaly, m_normalz );
		glVertex3f( m_x1, m_y1, m_z1 );
		glVertex3f( m_x2, m_y2, m_z2 );
		glVertex3f( m_x3, m_y3, m_z3 );
		glVertex3f( m_x4, m_y4, m_z4 );

		m_x2 = m_x4;
		m_y2 = m_y4;
		m_z2 = m_z4;

	} else if ( m_vertexCount == 5 ) {	
		m_x3 = x;
		m_y3 = y;
		m_z3 = z;	
		
	} else if ( m_vertexCount == 6 ) {	// need surface normals		
		m_x4 = x;
		m_y4 = y;
		m_z4 = z;

		findNormal();					// from 2, 3, 4

		glNormal3f( m_normalx, m_normaly, m_normalz );
		glVertex3f( m_x3, m_y3, m_z3 );
		glVertex3f( m_x4, m_y4, m_z4 );

		m_x2 = m_x4;
		m_y2 = m_y4;
		m_z2 = m_z4;
		m_vertexCount = 4;
	}
}

I initialize things here:

void CmyOGLView::IVme()	// called once to initialize screen and display list
{
	if (A.JDATSW[106] == 1) wndout("IVme\r\n");
	float tint = 0.0;
	if ( !m_blackonwhite ) {
		m_clearColor[1] = ( graphicsBK & 0xff )/255.0;
		m_clearColor[2] = (( graphicsBK & 0xff00 )/256.0 )/255.0;
		m_clearColor[3] = (( graphicsBK & 0xff0000 )/65536.0 )/255.0;
		m_clearColor[0] = 0.0;		// alpha		
	} else {
		tint = 1.0;
		m_clearColor[0] = tint;		// N/C
		m_clearColor[1] = tint;		// red
		m_clearColor[2] = tint;		// green
		m_clearColor[3] = tint;		// blue
	}

	m_dAlpha = 1.0;				// opaque
//	glShadeModel( GL_SMOOTH );
	glShadeModel( GL_FLAT );
	glEnable( GL_LIGHTING );
	glEnable( GL_LIGHT0 );
	glEnable( GL_LIGHT1 );
	glEnable( GL_DEPTH_TEST );
	glEnable( GL_BLEND );			// required for transparent effect
	glEnable( GL_NORMALIZE );
	glDisable( GL_COLOR_LOGIC_OP );
	glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
//	glEnable( GL_LINE_SMOOTH );		// makes fat dull lines
//	glEnable( GL_POLYGON_SMOOTH );	// makes gaps between panels

	goHome();					// initializations mostly there

	m_OGLlistName = glGenLists(1);
	m_OGLraylistName = glGenLists(2);
	glNewList( m_OGLlistName, GL_COMPILE_AND_EXECUTE );
}

And render the scene this way:

void CmyOGLView::RenderScene()
{	
		if (A.JDATSW[106] == 1) wndout("RenderScene\r\n");
	try {
		SwapBuffers( OGLhDC );
		glGetFloatv( GL_MODELVIEW_MATRIX, m_matrix );
	}

	catch (char *ErrorMsg) {
		wndout( ErrorMsg );
	}

}

Here’s a sample of the display:

image

Does this tell you what you need to know?

Following your suggestion, I have added some code to the OnDestroy():

	glDeleteLists( m_OGLlistName,1 );
	glDeleteLists( m_OGLraylistName,1 );
    HDC      hDC ;
    hDC = ::GetDC(m_hWnd); 

	wglMakeCurrent(hDC, NULL);
	wglDeleteContext(hRC);
	myOGLView = NULL;

	CScrollView::OnClose();
	CScrollView::OnDestroy();

This runs, but the memory is still not returned. What else can I try?

As you were. I think the

wglDeleteContext(hRC);

did the trick. Memory increases with each instance of the window – but only by a small amount. So I think the problem is fixed. Thank you very much!