【问题标题】:Memory leak in Delphi XE3 when error happens on inserting into sqlite db插入sqlite db时发生错误时Delphi XE3中的内存泄漏
【发布时间】:2013-01-10 18:38:35
【问题描述】:
...
Query: TSQLQuery
...
    Query.SQL.Clear;
    Query.SQL.Add('INSERT INTO pumps'#13#10 +
                       'VALUES (NULL, :title, :power)');
    Query.ParamByName('title').AsString:= title;
    Query.ParamByName('power').AsFloat:= power;
    try
      Query.ExecSQL;
    except
      on E: Exception do
        begin
          ShowMessage(E.Message);
        end;
    end;

查询通过 driver=Sqlite 链接到 SQLConnection。所有操作都有效,但是当我尝试将非唯一值插入具有唯一索引的列中时,我得到关于值存在的异常。好的,我的代码捕获它并显示一条消息“列标题不是唯一的”,但在调试器向我显示该异常 TWICE 之前。当我关闭程序时,内存管理器会告知内存泄漏,并且泄漏是:

  • 21 - 28 字节:UnicodeString x 4
  • 61 - 68 字节:TDBXSqliteCommand x2
  • 69 - 76 字节:TDBXMorphicCommand x 2
  • 221 - 236 字节:未知 x 2

可以避免吗?

UPD:我使用 FastMM4 获取详细日志,以下是关于内存泄漏的部分:

A memory block has been leaked. The size is: 68

This block was allocated by thread 0xB18, and the stack trace (return addresses) at the time was:
4068A6 [System.pas][System][@GetMem$qqri][4203]
4082BB [System.pas][System][TObject.NewInstance$qqrv][14969]
4089D2 [System.pas][System][@ClassCreate$qqrpvzc][16231]
7D5A91 [Data.DbxSqlite.pas][Data.DbxSqlite][Dbxsqlite.TDBXSqliteCommand.$bctr$qqrp26Data.Dbxcommon.TDBXContextp35Data.Dbxsqlite.TDBXSqliteConnection][567]
6E3DFE [Data.DBXCommon][Generics.Collections.%TDictionary__2$20System.UnicodeStringp32Data.Dbxcommon.TDBXCreateCommand%.GetBucketIndex$qqrx20System.UnicodeStringi]
7D4C8E [Data.DbxSqlite.pas][Data.DbxSqlite][Dbxsqlite.TDBXSqliteDriver.CreateSqliteCommand$qqrp26Data.Dbxcommon.TDBXContextp29Data.Dbxcommon.TDBXConnectionp26Data.Dbxcommon.TDBXCommand][295]
6CE4DA [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXDriver.CreateMorphCommand$qqrp26Data.Dbxcommon.TDBXContextp29Data.Dbxcommon.TDBXConnectionp26Data.Dbxcommon.TDBXCommand][7569]
6D5177 [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXDelegateDriver.CreateMorphCommand$qqrp26Data.Dbxcommon.TDBXContextp29Data.Dbxcommon.TDBXConnectionp26Data.Dbxcommon.TDBXCommand][11061]
6D09F4 [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXConnection.CreateMorphCommand$qqrp26Data.Dbxcommon.TDBXCommand][8480]
6D1C21 [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXMorphicCommand.DerivedOpen$qqrv][9084]
6D1974 [Data.DBXCommon.pas][Data.DBXCommon][Dbxcommon.TDBXCommand.Open$qqrv][8962]

The block is currently used for an object of class: TDBXSqliteCommand

【问题讨论】:

  • 我们可以假设发布唯一值时没有泄漏吗?
  • 你在调试器外运行程序时有泄漏吗?调试代码时我总是有 UnicodeString 泄漏...
  • 使用完整版的 FastMM 并获得一些真正的诊断。这将告诉您每个泄漏块的分配位置,并在分配点为您提供调用堆栈。没有这些信息,我们都束手无策。
  • 要了解@whosrdaddy 所说的内容,请参阅我的博文"when The Debugger Leaks..."
  • @Sertac Akyuz,是的,当记录正确存储并且数据库没有返回错误时,我没有泄漏。

标签: delphi sqlite


【解决方案1】:

我使用 dbXpress SQLiteMySQL 驱动程序 (XE3) 运行测试,而您的代码只是使用 SQLite 泄漏(在调试模式下也会出现双重异常),但它 不适用于 MySQL

恕我直言,这是一个应该报告给 QC 的错误。

在调试器中第一次发生异常时的堆栈跟踪

:769cc41f KERNELBASE.RaiseException + 0x58
Data.DBXCommon.TDBXContext.Error(???,'column title is not unique')
Data.DbxSqlite.CheckError(19,???,$2F12738)
Data.DbxSqlite.TDBXSqliteCommand.DerivedExecuteQuery
Data.DBXCommon.TDBXCommand.ExecuteQuery
Data.DBXCommon.TDBXMorphicCommand.ExecuteQuery
Data.SqlExpr.TCustomSQLDataSet.ExecuteStatement
Data.SqlExpr.TCustomSQLDataSet.ExecSQL(???)
Data.SqlExpr.TSQLQuery.ExecSQL(???)
Main_ViewU.TForm1.RunQuery($2E7B870,'Title',10)
Main_ViewU.TForm1.Button1Click($2E85AD0)

在调试器中第二次发生异常时的堆栈跟踪

:769cc41f KERNELBASE.RaiseException + 0x58    // <-- Exception interrupts Destroy
Data.DBXCommon.TDBXContext.Error(???,'column title is not unique')
Data.DbxSqlite.CheckError(19,???,$2F12738)
Data.DbxSqlite.TDBXSqliteCommand.DerivedClose
Data.DBXCommon.TDBXCommand.Close
Data.DBXCommon.TDBXMorphicCommand.DerivedClose
Data.DBXCommon.TDBXCommand.Close
Data.DBXCommon.TDBXCommand.Destroy            // <-- DESTROY
Data.DBXCommon.TDBXMorphicCommand.Destroy     // <-- DESTROY
System.TObject.Free
Data.SqlExpr.TCustomSQLDataSet.CloseStatement
Data.SqlExpr.TCustomSQLDataSet.InternalFreeCommand
Data.SqlExpr.TCustomSQLDataSet.FreeCommand
Data.SqlExpr.TCustomSQLDataSet.ExecSQL(???)
Data.SqlExpr.TSQLQuery.ExecSQL(???)
Main_ViewU.TForm1.RunQuery($2E7B870,'Title',10)
Main_ViewU.TForm1.Button1Click($2E85AD0)

这会导致内存泄漏......

【讨论】:

  • 谢谢。实际上,我了解 try ... finally,但我给出了一个代码来显示错误在执行 ExecSQL 期间准确出现,并且仅在数据库错误的情况下(在我的情况下,此错误是唯一索引上的重复值)。准确地说,TSQLQuery 是 DataModule 中的一个组件,但是,重复一遍,如果数据库响应没有错误,我就没有内存泄漏。
  • 哇!感谢您的研究。据我了解,我对 DBX 中的错误代码的假设是正确的,不是吗? :)。而且,很遗憾,我无法向 QC 报告错误。
  • 当然你可以向 QC 报告错误。任何人都可以这样做。如果您关心您使用的工具,那么您应该努力使其变得更好。
猜你喜欢
  • 2013-07-09
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 1970-01-01
  • 2013-07-14
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多