现在的位置: 首页 > 综合 > 正文

画图时 内存不停 增长 的解决 CreateCompatibleDC(NULL) 创建失败

2014年09月28日 ⁄ 综合 ⁄ 共 10096字 ⁄ 字号 评论关闭

今天做贪食蛇的时候,当吃了几个食物的时候,系统报错,我是在group上画图,蛇头,蛇尾,蛇身,三张位图。

CreateCompatibleDC(NULL) 创建失败,网上查了原因,应该是内存不足引起的,查看任务管理器,果然发现内存一直增长。

经过排查原因发现是dc没有释放。

 

 

 HDC memDc=CreateCompatibleDC(NULL);//这种的必须要释放 DeleteDC(memDc);//必须释放,要不占内存

 

但是 CDC sourceDC, destDC;

sourceDC.CreateCompatibleDC(NULL);

destDC.CreateCompatibleDC(NULL);

这种的就不用释放,内存不会增加,个人推测这种是包装过的类,应该是退出函数时,调用析构函数进行释放了。不需要显式释放。

 

类似的

CWnd *cw=GetDlgItem(IDC_GROUP_MAIN);
   HDC hdc=cw->GetDC()->GetSafeHdc();
 

这种通过 HDC来接受的就需要 显式的调用释放函数 DeleteDC(hdc);      cdc应该就不用

 

其中误解了很多地方占用内存没释放,事后发现其实没有,误解的地方:

cbitmap不用释放内存 和LoadBitmap 没有关系 和bitmap也没关系,不用手动释放

和还原原始设备也没关系 SelectObject(memDc,bitold);

和CArray<CPoint,CPoint&> arr_points; 没关系,他会自动释放,也不用removeall

 

另外。

个人觉得,这个是立刻释放内存的做法,这个应该不算内存泄露,因为debug的时候没有内存泄露的提示,而且,最小化后,再最大化,内存减了很多。

 

总结就是:指针和原始类需要手动释放内存,其他的不需要。

 

相关源代码如下:

// SnakeView.cpp : implementation of the CSnakeView class
//

#include "stdafx.h"
#include "Snake.h"

#include "SnakeDoc.h"
#include "SnakeView.h"
#include "GAMESET.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define  TimerMain 1
int GetRand(double MAX,double MIN);

HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack);
/////////////////////////////////////////////////////////////////////////////
// CSnakeView

IMPLEMENT_DYNCREATE(CSnakeView, CFormView)

BEGIN_MESSAGE_MAP(CSnakeView, CFormView)
//{{AFX_MSG_MAP(CSnakeView)
ON_WM_KEYDOWN()
ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BTN_START, OnBtnStart)
	ON_WM_SHOWWINDOW()
	ON_COMMAND(IDM_GAME_SET, OnGameSet)
	//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSnakeView construction/destruction

CSnakeView::CSnakeView():CFormView(CSnakeView::IDD),
	m_iDircFlag(3),m_changeTail(FALSE),m_iTailDegree(0),
	m_pFood(CPoint(0,0)),iRandomSeed(0),i_Speed(0)//默认是向右
{
	// TODO: add construction code here
	
}

CSnakeView::~CSnakeView()
{
}

BOOL CSnakeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	
	return CFormView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView drawing

void CSnakeView::OnDraw(CDC* pDC)
{
	
	CSnakeDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here

	int size=m_snake.m_points.GetSize();
	
 	for (int i=0;i<size;i++)
 	{
 		CBitmap bit;
 		//HBITMAP bitold;
 		HBITMAP hbitmap;
 		if (i==0||i==size-1)//表示是头或者尾巴
 		{
 			if (i==0)
 			{
 				bit.LoadBitmap(IDB_SHead);//头
  				int degree;
  				switch (m_iDircFlag)
  				{
  				case 0:
  					degree=90;
  					break;
  				case 1:
  					degree=-90;
  					break;
  				case 2:
  					degree=180;
  					break;
  				case 3:
  					degree=0;
  					break;
  				}
  				hbitmap=(HBITMAP)GetRotatedBitmapNT(bit,degree*3.14159265359/180,pDC->GetBkColor());//旋转图片
  				bit.Detach();
  				bit.Attach(hbitmap);
 			}
 			else
 			{
 				bit.LoadBitmap(IDB_STail);//尾巴
  				if (m_changeTail)
  				{
  					switch (m_iDircFlag)
  					{
  					case 0:
  						m_iTailDegree=90;
  						break;
  					case 1:
  						m_iTailDegree=-90;
  						break;
  					case 2:
  						m_iTailDegree=180;
  						break;
  					case 3:
  						m_iTailDegree=0;
  						break;
  					}
  					m_changeTail=FALSE;
  				}
  
  				hbitmap=(HBITMAP)GetRotatedBitmapNT(bit,m_iTailDegree*3.14159265359/180,pDC->GetBkColor());//旋转图片
  				bit.Detach();
  				bit.Attach(hbitmap);
 				
 			}
 		}
 		else
 		{
 			bit.LoadBitmap(IDB_SBody);
 		}
		
 		CWnd *cw=GetDlgItem(IDC_GROUP_MAIN);
 		HDC hdc=cw->GetDC()->GetSafeHdc();
 
 		HDC memDc=CreateCompatibleDC(NULL);
 		(HBITMAP)SelectObject(memDc,bit);
 		
 		BITMAP bm;
 		bit.GetBitmap(&bm);
 		CPoint cp=m_snake.m_points[i]; 
  
 		BitBlt(hdc,cp.x,cp.y+8,bm.bmWidth,bm.bmHeight,memDc,0,0,SRCCOPY);
 
 		DeleteDC(memDc);//必须释放,要不占内存
		DeleteDC(hdc);//必须释放,要不占内存
	}
	DrawFoodPoint();//画食物点
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView printing

BOOL CSnakeView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CSnakeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CSnakeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CSnakeView diagnostics

#ifdef _DEBUG
void CSnakeView::AssertValid() const
{
	CFormView::AssertValid();
}

void CSnakeView::Dump(CDumpContext& dc) const
{
	CFormView::Dump(dc);
}

CSnakeDoc* CSnakeView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSnakeDoc)));
	return (CSnakeDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CSnakeView message handlers

void CSnakeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default

	CFormView::OnKeyDown(nChar, nRepCnt, nFlags);
}

//蛇移动事件
void CSnakeView::Move()
{
	int size=m_snake.m_points.GetSize();
	CArray<CPoint,CPoint&> arr_points;//复制一个临时的数组
	arr_points.Copy(m_snake.m_points);
	//思路:移动时,除了第一个坐标根据上下左右的不同,重新赋值外,其他的坐标复制他们前面一个坐标的值。
 	CPoint origTail=m_snake.m_points[size-2];
	
	for (int i=1;i<size;i++)
	{
		m_snake.m_points[i]=arr_points[i-1];
	}

	//获取group范围 判断蛇的位置是否超出范围,如果是的话,则提示失败,重新开始
	CWnd *cGroupWnd=GetDlgItem(IDC_GROUP_MAIN);
	RECT groupRect;
	cGroupWnd->GetClientRect(&groupRect);
	BOOL blIsOut=FALSE;
	switch (m_iDircFlag)
	{
	case 0://上
		m_snake.m_points[0].y-=16;
		if (m_snake.m_points[0].y<groupRect.top)//超出范围
		{
			blIsOut=TRUE;
			break;
		}
		if (origTail.y!=m_snake.m_points[size-2].y)//判断倒数第二个的x,y是否变化,来决定尾巴图片是否旋转
		{
			m_changeTail=TRUE;
		}
		break;
	case 1://下
		m_snake.m_points[0].y+=16;
		if (m_snake.m_points[0].y+16>groupRect.bottom)//超出范围
		{
			blIsOut=TRUE;
			break;
		}
		if (origTail.y!=m_snake.m_points[size-2].y)
		{
			m_changeTail=TRUE;
		}
		break;
	case 2://左
		m_snake.m_points[0].x-=16;
		if (m_snake.m_points[0].x<groupRect.left)//超出范围
		{
			blIsOut=TRUE;
			break;
		}
		if (origTail.x!=m_snake.m_points[size-2].x)
		{
			m_changeTail=TRUE;
		}
		break;
	case 3://右
		m_snake.m_points[0].x+=16;
		if (m_snake.m_points[0].x+16>groupRect.right)//超出范围
		{
			blIsOut=TRUE;
			break;
		}
		if (origTail.x!=m_snake.m_points[size-2].x)
		{
			m_changeTail=TRUE;
		}
		break;
	}	
	
	if (blIsOut)
	{
		m_snake.Initialize();//重新初始化
		m_iDircFlag=3;//方向初始化
		m_changeTail=FALSE;//尾巴是否改变初始化
		m_iTailDegree=0;//尾巴角度初始化
		KillTimer(TimerMain);
		MessageBox("失败!");
	}

	//吃东西,如果头坐标和食物坐标相等,追加一个坐标
	if (m_snake.m_points[0].x==m_pFood.x&&m_snake.m_points[0].y+8==m_pFood.y)
	{
		m_snake.m_points.Add(arr_points[size-1]);
		CString cs;
		cs.Format("%d",m_snake.m_points.GetSize());
		SetDlgItemText(IDC_SNAKELEN,cs);
		GenerateFoodPoint();//生成食物点
	}	

	//重绘客户区
	RECT temprect(groupRect);
	temprect.right+=32;
	temprect.bottom+=32;
	InvalidateRect(&temprect);
}

// GetRotatedBitmapNT - Create a new bitmap with rotated image
// Returns - Returns new bitmap with rotated image
// hBitmap - Bitmap to rotate
// radians - Angle of rotation in radians
// clrBack - Color of pixels in the resulting bitmap that do
// not get covered by source pixels
HBITMAP GetRotatedBitmapNT( HBITMAP hBitmap, float radians, COLORREF clrBack )
{
	// Create a memory DC compatible with the display
	CDC sourceDC, destDC;
	sourceDC.CreateCompatibleDC(NULL);
	destDC.CreateCompatibleDC(NULL);
	// Get logical coordinates
	BITMAP bm;
	GetObject( hBitmap, sizeof( bm ), &bm );
	float cosine = (float)cos(radians);
	float sine = (float)sin(radians);
	// Compute dimensions of the resulting bitmap
	// First get the coordinates of the 3 corners other than origin
	int x1 = (int)(bm.bmHeight * sine);
	int y1 = (int)(bm.bmHeight * cosine);
	int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
	int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
	int x3 = (int)(bm.bmWidth * cosine);
	int y3 = (int)(-bm.bmWidth * sine);
	int minx = min(0,min(x1, min(x2,x3)));
	int miny = min(0,min(y1, min(y2,y3)));
	int maxx = max(0,max(x1, max(x2,x3)));
	int maxy = max(0,max(y1, max(y2,y3)));
	int w = maxx - minx;
	int h = maxy - miny;
	// Create a bitmap to hold the result
	HBITMAP hbmResult=::CreateCompatibleBitmap(CClientDC(NULL), w, h);
	HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
	HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
	// Draw the background color before we change mapping mode
	HBRUSH hbrBack = CreateSolidBrush( clrBack );
	HBRUSH hbrOld = (HBRUSH)::SelectObject(destDC.m_hDC, hbrBack );
	destDC.PatBlt( 0, 0, w, h, PATCOPY );
	::DeleteObject(::SelectObject(destDC.m_hDC, hbrOld));
	// We will use world transform to rotate the bitmap
	SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
	XFORM xform;
	xform.eM11 = cosine;
	xform.eM12 = -sine;
	xform.eM21 = sine;
	xform.eM22 = cosine;
	xform.eDx = (float)-minx;
	xform.eDy = (float)-miny;
	SetWorldTransform( destDC.m_hDC, &xform );
	// Now do the actual rotating - a pixel at a time
	destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
	// Restore DCs
	SelectObject(sourceDC.m_hDC, hbmOldSource );
	SelectObject(destDC.m_hDC, hbmOldDest );
	return hbmResult;
}

void CSnakeView::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	Move();//贪食蛇移动事件
	CFormView::OnTimer(nIDEvent);
}

BOOL CSnakeView::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	if (pMsg->message==WM_KEYDOWN)
	{
		switch (pMsg->wParam)
		{
		case VK_UP:
			m_iDircFlag=0;
			break;
		case VK_DOWN:
			m_iDircFlag=1;
			break;
		case VK_LEFT:
			m_iDircFlag=2;
			break;
		case VK_RIGHT:
			m_iDircFlag=3;
			break;
		}		
		Move();
	}
	return CFormView::PreTranslateMessage(pMsg);
}

void CSnakeView::OnBtnStart() 
{
	// TODO: Add your control notification handler code here
	if (i_Speed==0)
	{
		SetTimer(TimerMain,500,NULL);
	}
	else if (i_Speed==1)
	{
		SetTimer(TimerMain,300,NULL);
	}
	else
	{
		SetTimer(TimerMain,100,NULL);
	}
	
}

//画食物的点
void CSnakeView::DrawFoodPoint()
{
	CWnd *cwnd=GetDlgItem(IDC_GROUP_MAIN);

	CBitmap bit;
	bit.LoadBitmap(IDB_SBody);
	BITMAP bm;
	bit.GetBitmap(&bm);

	HDC hdc=CreateCompatibleDC(NULL);
	(HBITMAP)SelectObject(hdc,bit);
	HDC grouphdc=cwnd->GetDC()->GetSafeHdc();

	BitBlt(grouphdc,m_pFood.x,m_pFood.y,bm.bmWidth,bm.bmHeight,hdc,0,0,SRCCOPY);
	DeleteDC(grouphdc);
	DeleteDC(hdc);
}

//重新生成食物点
void CSnakeView::GenerateFoodPoint()
{
	if (iRandomSeed==0)
	{
		srand((unsigned)time(0));//用当前时间
	}
	else
	{
		srand(iRandomSeed);
	}
	iRandomSeed++;
	CWnd *cGroupWnd=GetDlgItem(IDC_GROUP_MAIN);
	RECT groupRect;
	cGroupWnd->GetClientRect(&groupRect);

	CBitmap bit;
	bit.LoadBitmap(IDB_SBody);
	BITMAP bm;
	bit.GetBitmap(&bm);

	while (TRUE)
	{
		BOOL blflag=FALSE;//是否需要重新生成food的点
		m_pFood.x=(int)(rand()%(groupRect.right/16))*bm.bmWidth;
		m_pFood.y=(int)(rand()%(groupRect.bottom/16))*bm.bmHeight+8;
		for (int i=0;i<m_snake.m_points.GetSize(); ++i)
		{
			if ((m_snake.m_points[i].x==m_pFood.x)&&(m_snake.m_points[i].y==m_pFood.y))
			{
				blflag=TRUE;
				break;
			}
		}
		if (!blflag)
		{
			break;
		}
	}
}

void CSnakeView::OnShowWindow(BOOL bShow, UINT nStatus) 
{
	CFormView::OnShowWindow(bShow, nStatus);
	GenerateFoodPoint();//生成点
	// TODO: Add your message handler code here
	
}

void CSnakeView::OnGameSet() 
{
	// TODO: Add your command handler code here
	GAMESET gms;
	
	if (IDOK==gms.DoModal())
	{
		i_Speed=gms.m_iSpeed;
	}
	
}

 

抱歉!评论已关闭.