반응형

Visual Studio C++에서 메모리 누수를 감지해 보자.

 

// 메모리 누수 감지를 위한 헤더 파일과 매크로 정의
#define _CRT_MAP_ALLOC
#include <crtdbg.h>

#ifdef _DEBUG
	#ifndef DBG_NEW
		#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
		#define new DBG_NEW
	#endif
#endif

void leak()
{
	int* p = new int;
	//delete p;
}

int main()
{	
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	// _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) - 자동 호출: 프로그램 시작
	// 부분에 한 번만 적어두면, 프로그램이 어디서 어떻게 종료되든 간에 종료되는 순간에 알아서
	// _CrtDumpMemoryLeaks()를 호출해주어 가장 편리하고 많이 쓰이는 방식.

	leak();

	int* p = new int;
	//delete p;

	p = new int;
	delete p;

	//_CrtDumpMemoryLeaks();
	// _CrtDumpMemoryLeaks() - 수동 호출: 원하는 특정 시점의 누수를 바로바로 검사하고 싶을 때 유용.
	// 하지만 프로그램이 여러 군데서 return으로 종료되거나 예외로 튕겨 나갈 경우, 일일이 종료
	// 직전에 함수를 넣어주기 번거롭다.

	return 0;
}

 

Ctrl+F5(Start Without Debugging)로 실행하면 아무것도 출력되지 않는다. F5(Start Debugging)로 실행해야 한다.

결과는 Output 윈도우에 출력된다.

 

 

첫 번째 메모리 누수가 발생하는 지점은 Source.cpp 파일의 27번째 라인이다. {165}의 의미는 프로그램이 시작되고 165번째 메모리 할당이 이루어졌다는 뜻이다. 아래와 같이 _CrtSetBreakAlloc()를 사용하면 165번째 메모리 할당이 되는 시점에 프로그램을 중단하고 디버거를 구동한다.

// 메모리 누수 감지를 위한 헤더 파일과 매크로 정의
#define _CRT_MAP_ALLOC
#include <crtdbg.h>

#ifdef _DEBUG
	#ifndef DBG_NEW
		#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
		#define new DBG_NEW
	#endif
#endif

void leak()
{
	int* p = new int;
	//delete p;
}

int main()
{
	_CrtSetBreakAlloc(165);
	// 특정 할당 번호에서 중단점 설정: 메모리 누수의 원인을 찾기 위해 특정 할당 번호에서
	// 디버거가 중단되도록 설정하는 함수.
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	// _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) - 자동 호출: 프로그램 시작
	// 부분에 한 번만 적어두면, 프로그램이 어디서 어떻게 종료되든 간에 종료되는 순간에 알아서
	// _CrtDumpMemoryLeaks()를 호출해주어 가장 편리하고 많이 쓰이는 방식.

	leak();

	int* p = new int;
	//delete p;

	p = new int;
	delete p;

	//_CrtDumpMemoryLeaks();
	// _CrtDumpMemoryLeaks() - 수동 호출: 원하는 특정 시점의 누수를 바로바로 검사하고 싶을 때 유용.
	// 하지만 프로그램이 여러 군데서 return으로 종료되거나 예외로 튕겨 나갈 경우, 일일이 종료
	// 직전에 함수를 넣어주기 번거롭다.

	return 0;
}

 

_CrtSetBreakAlloc()가 동작하여 디버거가 멈출 때, 내가 작성한 소스 코드가 아닌 new_debug.cpp 같은 알 수 없는 파일에서 멈추는 이유는 new나 malloc을 호출했을 때 실제 메모리를 할당하는 C++ 런타임 라이브러리(CRT)의 최하단 내부 코드에서 브레이크가 걸리기 때문이다.

 

Call Stack 윈도우에서 현재 위치 아래에 있는 내가 작성한 파일로 판단되는 위치에서 우클릭한다.

 

Go To Source Code를 클릭한다.

 

메모리 누수가 발생하는 곳에 커서가 표시된다.

 

출력을 콘솔로 바꾸고 싶다면 아래와 같이 작성한다.

// 메모리 누수 감지를 위한 헤더 파일과 매크로 정의
#define _CRT_MAP_ALLOC
#include <crtdbg.h>

#ifdef _DEBUG
	#ifndef DBG_NEW
		#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
		#define new DBG_NEW
	#endif
#endif

void leak()
{
	int* p = new int;
	//delete p;
}

int main()
{	
	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
	// _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF) - 자동 호출: 프로그램 시작
	// 부분에 한 번만 적어두면, 프로그램이 어디서 어떻게 종료되든 간에 종료되는 순간에 알아서
	// _CrtDumpMemoryLeaks()를 호출해주어 가장 편리하고 많이 쓰이는 방식.

	// 출력 모드를 콘솔(표준 에러 스트림)로 변경
	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);

	leak();

	int* p = new int;
	//delete p;

	p = new int;
	delete p;

	//_CrtDumpMemoryLeaks();
	// _CrtDumpMemoryLeaks() - 수동 호출: 원하는 특정 시점의 누수를 바로바로 검사하고 싶을 때 유용.
	// 하지만 프로그램이 여러 군데서 return으로 종료되거나 예외로 튕겨 나갈 경우, 일일이 종료
	// 직전에 함수를 넣어주기 번거롭다.

	return 0;
}

 

 

반응형
Posted by J-sean
:

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

반응형

간단한 멀티 스레드와 뮤텍스 사용 예를 확인해 보자.

 

뮤텍스를 사용하지 않은 멀티스레드.

#include <iostream>
#include <thread>

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		std::cout << "id: " << id << ", : " << i << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(1));	// 1초 대기
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

cout 출력 도중 컨텍스트 스위칭이 발생하며 출력이 엉망이 되어 버렸다.

 

뮤텍스를 사용한 멀티스레드.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		m.lock();
		std::cout << "id: " << id << ", : " << i << std::endl;
		m.unlock();
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

출력이 깔끔하다.

 

하지만 위 코드에 나오는 뮤텍스의 lock(), unlock()를 직접 호출하면 안 된다. 뮤텍스 락은 일종의 리소스이기 때문에 거의 대부분 RAII 원칙에 따라 독점적으로 획득된다. 뮤텍스에 락을 정확히 걸거나 해제하는 작업을 쉽게 처리할 수 있는 lock_guard, unique_lock 등의 락 클래스를 사용하자.

 

lock_guard를 사용한 뮤텍스 멀티 스레드.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;

void counter(int id, int max) {
	for (int i = 0; i < max; i++) {
		{
			// 락이 필요한 블럭
			std::lock_guard lock(m);
			std::cout << "id: " << id << ", : " << i << std::endl;
		}
		std::this_thread::sleep_for(std::chrono::seconds(1));
	}
}

int main() {
	std::thread t1(counter, 1, 10);
	std::thread t2(counter, 2, 10);

	t1.join();
	t2.join();

	return 0;
}

 

깔끔하고 안전한 출력.

 

반응형
Posted by J-sean
:
반응형

YOLOs-CPP를 빌드하고 간단한 예제를 만들어 보자.

 

2026.02.15 - [AI, ML, DL] - [YOLO] YOLOs-CPP build 빌드하기

 

CPU 사용 예.

#include "yolos/yolos.hpp"

int main() {
	// Initialize Use CPU
	yolos::det::YOLODetector detector("yolo11n.onnx", "coco.names", false);
	
	// Detect
	cv::Mat frame = cv::imread("catsdogs.png");
	std::vector<yolos::Detection> detections = detector.detect(frame, 0.25f, 0.45f);

	// Process results
	for (const yolos::det::Detection& det : detections) {
		std::cout << "Class: " << det.classId << " Conf: " << det.conf << std::endl;
		std::cout << "Box: (" << det.box.width << ", " << det.box.height << ")" << std::endl;
	}

	// Visualize
	detector.drawDetections(frame, detections);

	// Show
	cv::imshow("frame", frame);
	cv::waitKey(0);
		
	return 0;
}

 

OpenCV가 Debug 모드로 빌드되어 불필요한 경고가 많다.

 

 

GPU 사용 예.

#include "yolos/yolos.hpp"

int main() {
	// Initialize Use GPU
	yolos::det::YOLODetector detector("yolo11n.onnx", "coco.names", true);
	
	// Detect
	cv::Mat frame = cv::imread("catsdogs.png");
	std::vector<yolos::Detection> detections = detector.detect(frame, 0.25f, 0.45f);

	// Process results
	for (const yolos::det::Detection& det : detections) {
		std::cout << "Class: " << det.classId << " Conf: " << det.conf << std::endl;
		std::cout << "Box: (" << det.box.width << ", " << det.box.height << ")" << std::endl;
	}

	// Visualize
	detector.drawDetections(frame, detections);

	// Show
	cv::imshow("frame", frame);
	cv::waitKey(0);
		
	return 0;
}

 

 

 

  • Performance Tips
    Reuse detector instances — Create once, infer many times
    Use GPU when available — 5-10x faster than CPU
    Adjust thresholds — Higher confidence = fewer detections, faster NMS
    Match input resolution — Use model's expected size (640x640)

 

※ 참고

Usage Guide

 

반응형
Posted by J-sean
:

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.