2017-09-03 14 views
0

모든 메모리 누수를 잡아 내 응용 프로그램에서 새/삭제 연산자를 오버로드하고 싶습니다. 그것은 리눅스에서 잘 작동합니다. 하지만 Windows에서 문제가 발생했습니다. 새/삭제 오버로드는 .exe에만 적용되고 .dll 파일에는 적용되지 않습니다. Furthemore 일부 개체가 내 코드에서 만들어 지지만 .dll 파일에서 삭제되면 앱이 다운됩니다. 어떤 소스 파일, 프로그램의 아무 곳이나 정의 된 동일한 서명을 가진 사용자가 제공하는 비 멤버 함수 기본 버전을 대체합니다 Cppreference hereMinWW에서 전역 과부하 연산자 새로 추가/삭제

버전 (1-8) 교체 말합니다. 그 선언은 일 필요는 없습니다.

나는이를 테스트하기 위해 최소한의 Qt 템플릿 응용 프로그램을 작성했습니다. 여기 mainwindow.cpp :

#include "mainwindow.h" 
#include "ui_mainwindow.h" 

#include <cstdio> 
#include <cstdlib> 

// replacement of a minimal set of functions: 
void *operator new(std::size_t sz) 
{ 
    void *ptr = std::malloc(sz); 
    std::printf("global op new called, size = %zu, pointer = 0x%p\n", sz, ptr); 
    return ptr; 
} 

void operator delete(void* ptr) noexcept 
{ 
    std::printf("global op delete called, pointer = 0x%p\n", ptr); 
    std::free(ptr); 
} 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
} 

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 

출력 :

global op new called, size = 20, pointer = 0x00c4f608 
global op new called, size = 24, pointer = 0x00c4f648 
global op new called, size = 16, pointer = 0x00b35bf8 
global op new called, size = 24, pointer = 0x00c4f6a8 
global op new called, size = 24, pointer = 0x00c4f868 
global op new called, size = 24, pointer = 0x00c4f988 
global op delete called, pointer = 0x00c4f608 

그것은 Qt는 4.8.7/GCC 4.8.2과 Qt는 5.5.1/GCC 4.9.2 테스트되었습니다. 그렇다면 MinGW에서 전역 적으로 새로운/삭제를 오버로드하는 방법은 무엇입니까?

P. S. 문제를 재현하기 위해 최소 test case이라고 적었습니다. 출력 됨

$ ./main.exe 
global op new called, size = 4, pointer = 0x003e17b8 
global op new called, size = 4, pointer = 0x003e3d68 
library delete called, pointer = 0x003e17b8 
global op delete called, pointer = 0x003e3d68 
+0

EXE/DLL 문제의 경우 공유 DLL C 런타임 지원을 사용하고 있는지 확인해야합니다. 그렇지 않다면 2 개의 분리 된 힙을 가질 것이고 (하나는 각 모듈에 하나씩), 하나의 malloc은 다른 하나로부터'자유 '될 수 없다. –

+0

나는 dll에서 메모리를 확보하지 않는 것이 좋습니다. 이를 할당하는 구성 요소에 메모리를 할당 해제하는 책임을 할당하는 것이 좋습니다. – jumper0x08

+0

jumper0x08, 피할 수 없습니다. 부모를 삭제할 때 모든 어린이를 삭제하면 Qt에 대한 완전히 올바른 동작입니다. 템플릿의 최소 Qt 응용 프로그램 (.exe)은 개체 계층 구조를 만들고 루트 개체 만 삭제합니다. 어린이는 Qt 라이브러리 (.dll)에서 삭제됩니다. –

답변

0

GCC Bugzilla에서 답변을 찾았습니다 - Bug 77726.

리우 하오 쓴 :

당신이 Windows에서 동적 연결 라이브러리 (DLL)를 리눅스에서 공유 객체 (SO)와 다른 작동 방법을 알고 있다면 그것은 weired되지

.

Windows에 Linux에서 ld.so과 같은 동적 링커가 없습니다. DLL의 기호는 Linux와 달리 빌드 타임에 해결됩니다. SO의 기호가로드 시간에 해석되는 기호입니다. DLL 로더는 심볼을 주소로 해석 할 수 있지만 링커 만큼 강력하지는 않습니다. 따라서 실행 파일은 강한 기호 을 사용하여 DLL에서 이미 해결 된 약한 기호를 재정의 할 수 없습니다.

사용자가 크기 할당 해제 함수를 정의하지 않으면 libstdC++ *에 기본값 이 있습니다.DLL이 빌드되어 무시 될 수없는 유일한 후보 인 같은 DLL에서 약한 기본값 인 크기가 아닌 할당 해제 함수를 호출하는 dll이 사용됩니다.

0

Windows는 Linux가 아니므로 이에 따라 행동해야합니다.

간단히 말하면, 일반적으로 각 EXE/DLL이 자체 메모리를 관리 할 수 ​​있도록하는 것이 안전합니다. 즉, EXE/DLL에 의해 할당 된 메모리는 동일한 EXE/DLL에 의해서만 할당 해제되어야합니다. 이는 DLL이 createObj 기능을 제공 할 때 destroyObj 기능을 제공해야 함을 의미합니다. 물론 모든 EXE와 DLL이 동일한 런타임 DLL (동일한 버전 및 정적 런타임 없음)을 사용할 수 있도록 보장 할 수 있으면이 작업을 수행 할 필요가 없습니다. 이 경우에도 EXE와 DLL은 operator new/delete을 공유하지 않습니다.

메모리 디버거를 사용하는 경우 개체 파일을 각 EXE 및 DLL에 연결해야합니다. 각 EXE/DLL은 자체 메모리 할당자를 가지며 자체적으로 감지합니다.