Memory Leak 검출해 주는 오픈소스

예전에 VC6.0을 사용할때 코딩하고 Debug로 컴파일하면 어느 지점에서 메모리 누수(Leak)가 발생하는지 IDE의 출력창에서 알려주었다. 원래 VC6.0이 그랬는지, 아니면 나도 모르게 뭔가를 설치해서 그랬는지는 기억나지 않지만 말이다. 그런데 VS2003 이후로는 메모리 누수에 대한 보고를 해주지 않는 것이다. 난 한동안 아.. 메모리 누수가 발생하지 않게 잘했나보다 했는데.. 그게 아니란것을 알고 난후, 메모리 누수를 검출해주는 툴을 찾다가 괜찬은 녀석 둘을 만났다.

http://www.codeproject.com/tools/visualleakdetector.asp
http://www.codeproject.com/tools/leakfinder.asp

간단히 소개를 하면, 첫번째는 라이브러리를 Link해주고 vld.h라는 헤더파일 하면 include 해주면 메모리 누수 검출의 준비가 끝난다. 누수의 결과는 IDE 창에서 해주게 되는데 아래의 코드를 작성하고 컴파일하면 IDE의 출력창에 누수의 지점과 내용을 출력해준다.

#include "vld.h"

int main()
{
    char *pChar = new char[100];

    return 0;
}

이것은 필자가 VS6.0에서 경험했던 바로 그것이였다. 그러나 단점은 프로젝트의 코드생성이 다중스레드DLL이냐, 그냥 다중스레드냐에 따라 다른 라이브러리를 링크해줘야 한다는 것과 CRT 메모리에 대한 누수만을 검출해주며 COM 메모리 누수는 검출해주지 못한다. 즉, COM군의 함수중에 메모리를 할당해주는 CoTaskMemAlloc 함수에 대한 메모리 누수는 검출해주지 못하는 것이다. 그러나 IDE와 연동되어 IDE의 출력창에서 누수에 대한 정보를 더블클릭하면 누수지점의 코드로 커서가 이동하는 기능은 상당히 매력적이다.

끝으로 두번째는. 하나의 헤더파일과 그에 대한 하나의 소스파일로 구성되는 간단한 구조인데, StackWalker.h 파일을 include 해주고 누수검출 시작과 끝을 지정하는 함수를 호출해줌으로써 메모리 누수 검출의 준비가 끝나게 되어 무척 사용하기가 쉽다. 게다가 CRT 메모리 뿐아니라 COM 메모리에 대한 누수검출까지 가능하다. 또한 메모리 누수에 대한 정보는 3가지로 구분되는데, 간단한 SImple 모드, 좀더 자세한 Advanced 모드, XML 모드이다. 모두 외부 파일을 통해 누수 정보를 개발자에게 Report한다. 하지만 첫번째 소개했던 누수툴과는 달리 IDE와 연동을 지원해주지 않는다는 단점이 있다.

플렛폼이 Windows라는 범위에만 초점을 맞춰볼적에 비록, 최근의 추세가 Garbage Collection에 의한 자동 메모리 정리 기능이 있어, 메모리 누수에 대한 염려가 많이 줄기는 하였지만, .NET에서 지원하는 C++/CLI는 CLR 메모리만이 아니라, CRT, CLR, Stack 메모리에 까지 접근이 가능하므로 메모리 누수에 대해 주의를 요한다는 점에서 아직까지 이러한 메모리 누수 검출 도구는 유용하다고 하겠다.

[참고] 아래 글의 “줘도 못먹는”에 해당하는 오프소스가 아닙니다.

놀고 있는 비디오 메모리 활용

비디오 카드의 메모리의 용량은 적게는 32M에서 256M 정도 된다. 흔히 128M 정도의 카드가 많이 사용된다. 이 많은 비디오 카드의 메모리는 렌더링의 속도를 향상 시키기 위해서 3차원 그래픽 프로그램에서 사용된다. 하지만 3차원 그래픽 프로그램이 구동되지 않을 경우 대부분의 비디오 카드 메모리는 사용되지 않고 낭비된다. 예를들어 필자의 경우 해상도 1280×1024에서 32비트 색상을 사용하고 비디오 카드의 메모리는 128M이므로 128M에서 약 5M를 뺀 약 120M 정도의 비디오 메모리가 놀고 있는 셈이다.

그렇다면 이렇게 낭비되는 비디오 카드의 메모리를 3D 그래픽의 사용 목적이 아닌 일반 메모리처럼 사용할 수는 없을까? 게다가 비디오 카드의 메모리는 일반 메모리에 비해서 그 속도가 훨씬더 빠르다는 장점이 있지 않은가?

비디오 메모리를 사용하기 위해서는 당연히 비디오 메모리에 접근할 수 있어야 한다. 비디오 메모리에 접근하기 위한 API가 필요한데, 접근을 위한 특별한 API 라이브러리를 사용하는게 아니라 OpenGL과 DirectX의 API를 사용하면 되겠다. 여기서 필자에게 익숙한 OpenGL API를 사용하도록 하겠다.

비디오 메모리와 관련된 OpenGL API는 다음과 같다.

– glBindBuffer
– glBufferData
– glBufferSubData
– glDeleteBuffers
– glGenBuffers
– glMapBuffer
– glUnmapBuffer

위의 API는 ARB 군에 속해 있다가 OpenGL 1.5부터는 표준으로 안착되었다. 즉, OpenGL 1.5 이전에는 위의 함수명에다 접미사격으로 ARB를 붙여 사용해야 한다. 예를 들어서 glBindBuffer의 경우 glBindBufferARB 처럼 말이다. 물론 ARB의 경우는 Extension이므로 지원하는지의 여부를 먼저 확인해야 할 것이다. 확인을 위한 문자값은 GL_ARB_vertex_buffer_object이다.

각 함수의 내용에 대한 설명은 생략하고 사용하는 방법에 대해서만 살펴보겠다. 먼저 OpenGL을 초기화하고 현재 그래픽 카드가 지원하고 있는 OpenGL의 버전이 1.5 이상인지를 확인해야 한다. 여기서 한가지 문제점이 있는데, 그것은 바로 OpenGL의 초기화이다. OpenGL을 초기화하지 않으면 해당 API의 진입점을 찾지 못한다. 하지만 3D 기능을 사용하지도 않을 것인데, OpenGL을 초기화하해야한다는 것은 어쩌면 큰 부담이다. 특히 Console 프로그래밍과 같은 경우 렌더링 창에 대한 DC를 얻어와야 OpenGL을 초기화할 수 있는데, 이런 경우에 필자는 바탕화면의 DC를 사용하였다. 초기화를 위해 바탕화면의 DC를 사용하였을뿐, 실제로 무엇인가 렌더링하지는 않았기때문에 별 문제는 없으리라 본다.

어찌되었든 OpenGL을 초기화하고 OpenGL의 버전이 1.5 이상인 경우 위의 API의 진입점 포인트를 성공적으로 얻어왔다면 이제 사용하는 일만 남았다.

사용하는 방법은 정말 간단하다. 일반 메모리의 포인터를 얻어와 사용하는 방법과 유사하기 때문이다.

GLuint bufferID;

glGenBuffers(1, &bufferID);
glBindBuffer(GL_ARRAY_BUFFER, bufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(BYTE)*allocMemSize, NULL, GL_STATIC_DRAW);
BYTE *pBuffer = (BYTE *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);

먼저 glGenBuffers를 사용하여 비디오 카드 메모리 버퍼의 ID를 생성하고 이 메모리 버퍼를 GL_ARRAY_BUFFER와 묶기 위해 glBindBuffer 함수를 사용한다. 그 후에 glBufferData를 사용하여 실제 비디오 메모리를 원하는 크기만큼 할당하는데 이 경우 가장 빠른 속도를 위해 GL_STATIC_DRAW를 사용하였다. 할당할 메모리의 크기는 자신이 사용하는 비디오 카드의 메모리의 크기를 잘 고려해서 지정하기 바란다. 여기까지 성공하였다면 할당 받은 비디오 카드의 메모리를 일반 메모리의 포인터처럼 사용하기 위해 메모리 주소값으로 Mapping 시키기 위해 glMapBuffer함수를 사용하여 포인터 주소를 얻어 온다. 바로 이 포인터 주소를 사용해서 일반 메모리와 똑같이 사용할 수 있는 것이다.

for(size_t i=0; i

위의 코드는 실제로 비디오 카드의 메모리를 마치 일반 포인터의 개념처럼 사용하는 예를 든 것이다.

이제는 이렇게 사용한 비디오 카드의 메모리를 해제시키는 방법은 다음 코드와 같다.

glUnmapBuffer(GL_ARRAY_BUFFER);
glDeleteBuffers(1, &bufferID);

필자가 시험삼아 10M의 메모리를 비디오 카드에 할당해 사용하는 방법과 일반 메모리에 new 연산자를 이용해 힙에 할당해서 사용하는 방법의 속도 차이를 비교해본 결과 약 3배정도의 속도 향상이 있음을 발견했다.

끝으로 이런 비디오 카드의 메모리의 속도의 장점을 잘활용한다면 빠른 속도를 요구하는 코드에 더욱 좋은 성능 향상을 꾀할 수 있을 것이다. 또한 비디오 메모리의 경우 일반 메모리에 비해 외부의 어플리케이션으로부터의 메모리 해킹이 어렵기 때문에 보안적인 면에서도 좋은 이점이 있을 것으로 생각된다.

오라클 OCI 클래스

2004년에 만들어 썼던 OCI 클래스입니다. OCI는 Oracle Call Interface의 약자(방금전까지 C가 Common인지, C언어의 C인지 해깔렸다는 ㅡㅡ;)이구요.

별도의 ODBC, OLEDB 등과 같은 MS의 데이터연결을 위한 설정 없이 오라클 서버에 연결하여 쿼리를 날릴 수 있구요. OCI를 이용한 데이터 처리는 속도면에서 그 어떤 방법보다 빠릅니다.

오라클 예제 소스를 보고 클래스화한 것이구요. 메모리릭은 아직 발견하지 못했구요. 아래는 예제 코드입니다.

#include "OCIw.h"

int main() {
    COCIw OCI;
    OCI.OpenDB("oragis", "scott", "tiger");

    OCI.ExecuteDML("INSERT INTO TEST2 (NAME, AGE) VALUES ('김형준', 29)");
    OCI.ExecuteDML("INSERT INTO TEST2 (NAME, AGE) VALUES ('홍길동', 27)");

    OCI.Query("SELECT * FROM TEST2");
    OCI.DisplayRecords();

    OCI.CloseDB();

    return 0;
}

OCIw.h 파일에 선언된 COCIw 클래스가 주인공입니다. 자유롭게 사용하시길….. 버그나 개선점은 댓글로……

원하는 수의 배수로 맞춰주는 코드

어떤 수 x가 있다고 할때, x가 자신보다 크면서 원하는 수의 최소 배수인 수를 구하는 간단한 코드. 활용처는… 예를들어, 비트맵의 가로크기를 8의 배수나 4의 배수로 맞출때 요긴하겠네요.

size_t x = 1;
size_t align_ = 8;
cout << ((x + (align_-1)) & ~(align_-1));

x는 어떤 수, align_은 맞추고자하는 배수. 결과는 콘솔로 출력되겠죠..

[출처] Applied C++