2010-12-01 2 views
1

내가 같이, SQLite는 데이터베이스에 액세스 할 QT 4.5.3을 사용하고 누수의 원인 :열기 데이터베이스는 메모리

<error> 
    <unique>0x5b</unique> 
    <tid>1</tid> 
    <kind>Leak_DefinitelyLost</kind> 
    <what>986 (384 direct, 602 indirect) bytes in 1 blocks are definitely lost in loss record 23 of 23</what> 
    <leakedbytes>986</leakedbytes> 
    <leakedblocks>1</leakedblocks> 
    <stack> 
    <frame> 
     <ip>0x4006D3E</ip> 
     <obj>/opt/valgrind341/lib/valgrind/x86-linux/vgpreload_memcheck.so</obj> 
     <fn>malloc</fn> 
     <dir>/home/slawomir/valgrind-3.4.1/build/valgrind-3.4.1/coregrind/m_replacemalloc</dir> 
     <file>vg_replace_malloc.c</file> 
     <line>207</line> 
    </frame> 
    <frame> 
     <ip>0x67FADC4</ip> 
     <obj>/usr/lib/libsqlite3.so.0.8.6</obj> 
     <fn>sqlite3_malloc</fn> 
    </frame> 
    <frame> 
     <ip>0x67FAF13</ip> 
     <obj>/usr/lib/libsqlite3.so.0.8.6</obj> 
    </frame> 
    <frame> 
     <ip>0x6816DA3</ip> 
     <obj>/usr/lib/libsqlite3.so.0.8.6</obj> 
    </frame> 
    <frame> 
     <ip>0x68175FD</ip> 
     <obj>/usr/lib/libsqlite3.so.0.8.6</obj> 
     <fn>sqlite3_open16</fn> 
    </frame> 
    <frame> 
     <ip>0x40DDEF9</ip> 
     <obj>/usr/lib/qt4/plugins/sqldrivers/libqsqlite.so</obj> 
    </frame> 
    <frame> 
     <ip>0x7F34AE0</ip> 
     <obj>/usr/lib/libQtSql.so.4.5.2</obj> 
     <fn>QSqlDatabase::open()</fn> 
    </frame> 
    </frame> 
    </stack> 
</error> 

사람이 누수를 해결하는 방법을 알고 있나요 :

void test_failed_connection() 
{ 
    db obj("/"); 
    TS_ASSERT_THROWS(obj.open(), DatabaseError); 
} 

나는 Valgrind의에 의해보고 된 메모리 누수를 얻을?

+0

@DumbCode 아무것도 최적화하려고하지는 않지만 코드를 단위 테스트하려고합니다. 문제는 데이터베이스를 여는 데 문제가있을 때 사례를 테스트하는 방법입니다. 이 예제에서 볼 수 있듯이 "/"(루트 디렉토리)를 데이터베이스 이름으로 전달하여이 경우를 에뮬레이션합니다. –

답변

3

Qt 및 sqlite 소스를 통해 찾아 보았습니다. 흥미 롭습니다. sqlite3_close 그것을 전달하여 오류가 열릴 때, 데이터베이스 연결 핸들과 연관된 자원이 해제되어야 발생 여부

: sqlite3_open16(), http://www.sqlite.org/c3ref/open.html에 대한 설명서를 읽기

, 하나는 다음과 같은 인용을 찾아()가 더 이상 필요하지 않을 때.

QSQLiteDriver::close() 오픈 전화의 경우에만 http://qt.gitorious.org/qt/qt/blobs/4.7/src/sql/drivers/sqlite/qsql_sqlite.cpp이 호출 된 것처럼 보입니다. SQLite의 설명서에 따르면 sqlite3_close()을 대문자로 지정해야합니다.

반면에 http://www.sqlite.org/c3ref/close.html은 핸들에 대해 NULL이 전달되면 no-op라고 주장합니다 (열려 있지 않은 경우). SQLite 소스 코드 (DIY - 웹 소스 브라우저 인터페이스를 모른다는 것)를 살펴보면 NULL으로 호출하면 반환된다는 것을 확인할 수 있습니다.

음 - 지금 문제의 핵심적 견실 한 재미 ...

순진를 위해, 하나는 sqlite3_open*()의 실패가 NULLdB 핸들을 의미하는 것으로 가정합니다. 그러나 SQLite의 소식통에 따르면 main.copenDatabase()을 읽었습니다. 그 호출은 실패 할 수 있지만 여전히 NULL db 핸들을 반환합니다.

DB 연결을 여는 데 실패했다고 가정하면 Qt는 NULL db 핸들을 받는다는 의미입니다. 그러나 그것은 SQLite가하는 것이 아닙니다. 그러나 문서가 더 명확해질 수 있습니다.

QSQLiteDriver::open()에 해당 내용을 추가하고 누출이 수정되었는지 확인하십시오. 그렇다면 Qt 녀석들에게 버그를 제출하고 다른 사람들은 SQLite 사람들에게 문서를 명확히 해달라고 요청하십시오 .-)

+0

당신을 위해 그렇게 할 RAII 객체를 더 잘 생성하십시오. 필연적으로 누출되지 않을 것이라고 기대하지는 않지만 Qt가 자원을 올바르게 정리하는 자동 객체를 제공 할 것으로 기대합니다. – CashCow

+0

@CashCow : SQLite가 NULL이 아닌 모든 핸들을 닫을 것을 요구하는 경우라면, Qt가 버그를 일으키지 않는다면 버그가됩니다. 별거 아니야. 버그가 수정되었습니다. –

+0

@CashCow : 의도적으로 QSQL은 RAII를 사용하지만 문제를 해결하면 구현 및 디자인 의도가 일치해야합니다. –

0

귀하의 코드

realdb.reset(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", "ConnName")));

가 컴파일 이유는 확실하지 않다, 오히려 이상한 보인다. QSqlDatabase *를 매개 변수로 사용하는 QSqlDatabase의 생성자가 표시되지 않습니다.

QSqlDatabase :: addDatabase를 호출하여 QSqlDatabase *를 반환 한 다음 new를 사용하여 다른 QSqlDatabase를 생성하고이를 매개 변수로 전달했습니다.

대신 auto_ptr은 당신이 부스트를 사용할 수 있습니다 :: shared_ptr의 다음

realdb.reset(QSqlDatabase::addDatabase("QSQLITE", "ConnName"), QSqlDatabase::removeDatabase);

리셋이 열려 쿼리가있는 경우 자원 누출을 떠날 수 removeDatabase을 조심하십시오.

+0

다시보세요. auto_ptr의 생성자는 포인터를 필요로합니다. open() 메서드에서 연결을 열고 데이터베이스를 열려고합니다. 소멸자에서 QSqlDatabase 개체를 소멸시키고 연결을 제거하므로 리소스가 누출되지 않습니다. –

+0

이 클래스는 복사 가능하지 않아야한다고 언급하는 것을 잊었습니다 (boost :: noncopyable로부터 상속 됨). 그러므로 shared_ptr을 사용할 경우이 경우 auto_ptr을 사용하는 것과 같습니다. –

+0

개체를 생성하는 QSqlDatabase에서 new를 호출하고 있습니다. 인터페이스는 QSqlDatabase에 공용 생성자를 제공하지 않지만, 생성하려면 QSqlDatabase :: addDatabase를 호출해야합니다. 따라서 잘못된 문서를보고 있지 않는 한 코드가 컴파일되는 것에 놀랐습니다. – CashCow

관련 문제