Archive

Posts Tagged ‘C’

วิธีตรวจจับ Memory Leak โดยง่ายของ Visual C++

วิธีนี้จะตรวจจับได้เฉพาะ Memory ที่ Alloc โดยใช้ฟังชั่นของ CRT (C-Runtime) เท่านั้นนะคับ เช่น malloc, realloc, operator new ฯลฯ และจะต้องเป็น Debug Build เท่านั้น หากเป็น Release Build ตัวตรวจจับจะถูกถอดออกอัตโนมัติ ส่วน Memory ที่ Alloc โดยใช้ฟังชั่นนอกเหนือจากนั้น (เช่น HeapAlloc ของ Win32 API) จะไม่สามารถตรวจจับด้วยวิธีนี้ได้ โดยการตรวจจับจะรายงานผลตอนที่โปรแกรมจบการทำงานแล้วผ่านทาง Debug Message ซึ่งดูได้ด้วยโปรแกรม DebugView หรือช่อง Output ของ Visual Studio หาก Debug ใน Visual Studio

วิธีการคือ ให้เรียกฟังชั่น _CrtSetDbgFlag (ต้อง include crtdbg.h เข้ามาก่อน) แบบตัวอย่างด้านล่างตอนที่โปรแกรมเริ่มการทำงาน

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

ตัวอย่างการใช้งานใน DllMain

#include <crtdbg.h>

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /* lpReserved */)
{
	if (DLL_PROCESS_ATTACH == ul_reason_for_call)
	{
		DWORD dwResult, dwBufferSize;
		wchar_t *pszModuleName;

		// Enable C-Runtime memory leak reporter
		_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

		// Get Module Name
		pszModuleName = nullptr;
		dwBufferSize = MAX_PATH / 2;

		do
		{
			free(pszModuleName);
			pszModuleName = reinterpret_cast<wchar_t *>(malloc((dwBufferSize *= 2) * sizeof(wchar_t)));

			dwResult = GetModuleFileName(hModule, pszModuleName, dwBufferSize);
		} while (dwResult == dwBufferSize);

		PathStripPath(pszModuleName);

		g_pszModuleName = pszModuleName;

		// Init WTL
		_Module.Init(NULL, hModule);
	}
	else if (DLL_PROCESS_DETACH == ul_reason_for_call)
	{
		// Free allocated memory
		free(const_cast<wchar_t *>(g_pszConfigDirectory));
		free(const_cast<wchar_t *>(g_pszNppDirectory));
		free(const_cast<wchar_t *>(g_pszModuleName));

		// Terminate WTL
		_Module.Term();
	}

	return TRUE;
}

ตัวอย่างการรายงานผล

Advertisements
Categories: C, C++, Programming, Software Development Tags:

Performance ระหว่าง i++ และ ++i

คนเก่งหลายๆคน มักจะใช้ ++i แทนการใช้ i++ ใน for ลูป โดยคิดว่า มันทำงานเร็วกว่า i++ ซึ่งก็ไม่แปลกที่จะคิดแบบนั้น เพราะตัวผมเองก็เห็นคำตอบของชาวต่างชาติหลายคนบอกไว้แบบนี้เหมือนกัน แต่ในความเป็นจริงแล้ว บน Visual C++ มันไม่ต่างกันเลย

เมื่อ Visual C++ คอมไพล์ Code นี้

int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 0; i < argc; ++i)
		_tprintf(_T("%d"), i);

	return 0;
}

Code ที่ได้จะเป็น

	mov	DWORD PTR _i$5259[ebp], 0
	jmp	SHORT $LN3@wmain
$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax
$LN3@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	cmp	eax, DWORD PTR _argc$[ebp]
	jge	SHORT $LN1@wmain
; Line 10
	mov	esi, esp
	mov	eax, DWORD PTR _i$5259[ebp]
	push	eax
	push	OFFSET ??_C@_15KNBIKKIN@?$AA?$CF?$AAd?$AA?$AA@
	call	DWORD PTR __imp__wprintf
	add	esp, 8
	cmp	esi, esp
	call	__RTC_CheckEsp
	jmp	SHORT $LN2@wmain

และเมื่อคอมไพล์ Code นี้

int _tmain(int argc, _TCHAR* argv[])
{
	for (int i = 0; i < argc; i++)
		_tprintf(_T("%d"), i);

	return 0;
}

Code ที่ได้จะเป็น

	mov	DWORD PTR _i$5259[ebp], 0
	jmp	SHORT $LN3@wmain
$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax
$LN3@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	cmp	eax, DWORD PTR _argc$[ebp]
	jge	SHORT $LN1@wmain
; Line 10
	mov	esi, esp
	mov	eax, DWORD PTR _i$5259[ebp]
	push	eax
	push	OFFSET ??_C@_15KNBIKKIN@?$AA?$CF?$AAd?$AA?$AA@
	call	DWORD PTR __imp__wprintf
	add	esp, 8
	cmp	esi, esp
	call	__RTC_CheckEsp
	jmp	SHORT $LN2@wmain

สังเกตตรง

$LN2@wmain:
	mov	eax, DWORD PTR _i$5259[ebp]
	add	eax, 1
	mov	DWORD PTR _i$5259[ebp], eax

จะเห็นว่ามันเหมือนกันเปะ

Categories: C, C++, Programming, Software Development Tags: