2012-06-12 77 views
1

我正在調試使用ADO進行數據庫連接的應用程序,主要是TAdoConnection和TAdoQuery 經過一些測試後,結果表明TAdoQuery持續消耗並且不釋放內存。 該問題可以很容易地與此代碼被再現:Delphi ADO內存消耗

procedure TForm1.RunQueries; 
var 
    Q: TADOQuery; 
    Conn: TADOConnection; 
begin 
    Conn := TADOConnection.Create(nil); 
    Conn.ConnectionString := 'Provider=PGNP.1;Password=*****;User ID=*****;Data Source=*****;Initial Catalog=*****;Extended Properties="PORT=5432"'; 
    Conn.LoginPrompt:=False; 
    Conn.Connected := true; 

    Q := TADOQuery.Create(nil); 
    Q.Connection := Conn; 
    Q.SQL.Text := 'select * from sometable where extract(year from now()-Field1)::int/60>=15 or Field2>=50 limit 5'; 

    q.Open; 
    q.Close; 
    FreeAndNil(Q); 
    FreeAndNil(Conn); 
end; 

如果這是一個帶有計時器在一些間隔(例如200毫秒)所消耗的存儲器保持與各種速度(每小時20-50MB)上升運行。 SQL文本本身並不真正相關。它也消耗內存'select * from Table1',只有更慢。帶有'delete ...'語句的ExecSQL似乎不會導致問題。

我用GetProcessMemoryInfo做了一些測試,看起來內存在使用Open方法之後被消耗並且沒有釋放。儘管如此,並非所有執行都會導致相同的內存增加。

這發生在使用PostgreSQL和不同ADO提供程序的開發服務器上,但我無法用MySQL重現它。使用http://www.pgoledb.com的ADO提供程序的其他應用似乎正常工作,所以問題不僅在於提供商 我嘗試了AQTime和FastMM4,但都報告沒有泄漏。 用D6和XE2構建的代碼工作原理相同。

我發現這個問題Delphi: TAdoQuery Memory Leak?,但問題出在代碼中的錯誤。

我的問題類似於這個錯誤報告http://qc.embarcadero.com/wc/qcmain.aspx?d=7018

您是否認爲這是Delphi中的一個bug,是否有解決方法?

更新: 即使對象是靜態的,實際上也會出現此問題。例如,一個Connection和Query組件放在表單上,​​並且連接保持打開狀態。只有Query SQL文本被更改並執行。

我試圖從PGfoundry.org安裝一個不同的提供者,但結果對我來說很奇怪。

兩個Postgres提供程序在不同的操作系統上出現內存泄漏,但不在MySQL中。我不確定那是什麼意思。如果這是一個VCL問題,它不應該總是存在嗎?如果不是,考慮到它發生在同一個數據庫服務器的不同提供者上,哪一層導致它?

+0

您是否將系統的MDAC更新爲最新版本?您是否嘗試直接訪問OleDB圖層 - 您可以嘗試[我們的開源單元](http://blog.synopse.info/post/2011/06/27/SynOleDB%3A-OpenSource-Unit-for-direct-接入到任何數據庫,通過-OLEDB)。 –

+0

QC註釋建議嘗試使用服務器端遊標而不是客戶端。你測試過了嗎? – whosrdaddy

+0

我更新了MDAC,並在Server 2008和2003兩個版本上測試,結果很不幸。 遊標對內存消耗也沒有影響。 至於直接訪問,我還沒有嘗試過,因爲我想避免重寫代碼的太多部分,這部分代碼非常大,而且不是我寫的。如果沒有其他選項,我也會嘗試。 – VGeorgiev

回答

1

我不知道這是否適用於您的情況,但過去與Windows Server 2008(也適用於Win7)連接到SQL Server時存在類似的內存問題。

有2倍的原因:

  1. 甲MS錯誤在導致泄漏的MDAC堆棧時ConnectionString中沒有包括Persist Security Info=true

  2. 的變化(「按設計」的行爲)在MS的Critical Section implementation不會釋放調試信息。

一個可能的解決方法是儘可能保持連接打開,而不是始終關閉並重新打開它們。

+0

謝謝你的建議。不幸的是,持久安全信息不會改變行爲。我更新了上面的問題以反映最新的測試。問題似乎與查詢本身有關,因爲它不受保持連接的影響。 – VGeorgiev

0

我在連接到DB2時遇到同樣的問題,因此您的問題不僅限於MS/SQL。我有一個線程在Embarcadero論壇上,但退出。我無法說服這些人說它不是我的代碼。即使當我把它放在最前面,我回來建議,這與問題完全沒有關係。 因爲我的過程是一個7/24/365多線程程序,所以我終於決定讓自己在調度程序下運行它,並且每天都關閉它。這是一個醜陋的修復,但我必須能夠爲我的客戶發票!

我也在C#中寫了一個小測試應用程序,看看我是否可以創建相同的問題。我沒有看到在那裏成長的記憶力。這是一個德爾福問題。