2017-03-23 71 views
5

Mam AV podczas zwalniania formularza, pojawia się, gdy kompresuję i wysyłam dane zestawu danych FireDAC do zdalnego serwera.AV po zwolnieniu formularza po skompresowaniu i przesłaniu danych TFDDataset

Jest to kod używam do kompresji danych, TFDDataset za:

function CompressDataset(Dataset: TFDDataset): TMemoryStream; 
var Data: TMemoryStream; 
    Compress: TZCompressionStream; 
begin 
    Result := TMemoryStream.Create; 
    Data := TMemoryStream.Create; 
    try 
    Compress := TZCompressionStream.Create(Result); 
    Dataset.SaveToStream(Data, TFDStorageFormat.sfBinary); 
    Data.Position := 0; 
    Compress.CopyFrom(Data, Data.Size); 
    finally 
    Data.Free; 
    Compress.Free; 
    end; 
    Result.Position := 0; 
end; 

I jest to kod, aby wysłać te dane skompresowane do zdalnego połączenia (DataSnap).

procedure TfrmRentFacturacion_Facturar.btnSendDesgloseClick(Sender: TObject); 
var Stream: TMemoryStream; 
begin 
    if qryFacturacion_Desglose.State = dsEdit then qryFacturacion_Desglose.Post; 

    Stream := CompressDataset(qryFacturacion_Desglose); 
    try 
    spActualizaDesglose.ParamByName('AStream').AsStream := Stream; 
    spActualizaDesglose.ExecProc; 
    finally 
    Stream.Free; 
    end; 
end; 

Kod ten pozostawia nieco niestabilny, najprawdopodobniej TFDDataset qryFacturacion_Desglose i podnosi AV podczas zwalniania formy. Ale nie rozumiem, co może być nie tak.

PS: Dzięki @J ... sugestii sprawdzenia stosu połączeń znalazłem źródło problemu. Jest to stos wywołań:

:000000000040E735 TObject.Free + $15 
:00000000007F1123 TParamObject.Destroy + $43 
:000000000041A155 TInterfacedObject._Release + $55 
:000007FEFF2211CE ; C:\Windows\system32\oleaut32.dll 
:0000000000459DAB VarClearDeep + $1B 
:0000000000459E6B @VarClear + $1B 
:0000000000459E7D @VarClr + $D 
:00000000004149F4 @VarClr + $14 
:0000000000414ACC @FinalizeArray + $BC 
:00000000004162F1 @DynArrayClear + $61 
:0000000000414B58 @FinalizeArray + $148 
:0000000000414985 @FinalizeRecord + $75 
:000000000040E82E TObject.CleanupInstance + $4E 
:000000000040E450 TObject.FreeInstance + $10 
:000000000040F1C1 @ClassDestroy + $11 
:000000000051ED43 TCollectionItem.Destroy + $43 
:000000000040E738 TObject.Free + $18 
:000000000051F40A TCollection.Clear + $5A 
:000000000051F1CD TCollection.Destroy + $2D 
:000000000084A858 TFDParams.Destroy + $88 
:0000000000838FD8 FDFree + $18 
:000000000084A8BB TFDParams.RemRef + $2B 
:0000000000B8C907 TFDCustomCommand.Destroy + $57 
:000000000040E738 TObject.Free + $18 
:00000000005419F3 TComponent.DestroyComponents + $93 
:000000000054117F TComponent.Destroy + $2F 
:0000000000B92A66 TFDCustomTableAdapter.Destroy + $86 
:0000000000B9BE02 TFDRdbmsDataSet.Destroy + $C2 
:000000000040E738 TObject.Free + $18 
:00000000005419F3 TComponent.DestroyComponents + $93 
:000000000054117F TComponent.Destroy + $2F 
:00000000006039C2 TControl.Destroy + $192 
:000000000060AA91 TWinControl.Destroy + $1B1 
:0000000000797273 TScrollingWinControl.Destroy + $73 
:0000000000798EB7 TCustomForm.Destroy + $1E7 
:000000000040E738 TObject.Free + $18 
:00000000007A1389 TCustomForm.CMRelease + $9 
:000000000040EE81 TObject.Dispatch + $41 
:0000000000607D56 TControl.WndProc + $386 
:000000000060EC07 TWinControl.WndProc + $8E7 
:000000000079ADB0 TCustomForm.WndProc + $910 
:000000000060DE4C TWinControl.MainWndProc + $2C 
:0000000000545056 StdWndProc + $26 
:00000000777D9BBD ; C:\Windows\system32\USER32.dll 
:00000000777D98C2 ; C:\Windows\system32\USER32.dll 
:00000000007A8E84 TApplication.ProcessMessage + $134 
:00000000007A8EF8 TApplication.HandleMessage + $18 
:00000000007A9364 TApplication.Run + $F4 
Impuestos.Impuestos 
:00000000776B59CD ; C:\Windows\system32\kernel32.dll 
:00000000778EA561 ; ntdll.dll 

AV pojawia się, gdy próbuje uwolnić Astream parametr spActualizaDesglose TFDStoredProc który wykonuje zdalne połączenie do DataSnap Server.

Po zmianie wywołania zmieniono sposób wywoływania, tak aby nie uwolnił oryginalnego strumienia danych.

procedure TfrmRentFacturacion_Facturar.btnSendDesgloseClick(Sender: TObject); 
    var Stream: TMemoryStream; 
    begin 
     if qryFacturacion_Desglose.State = dsEdit then qryFacturacion_Desglose.Post; 

     Stream := CompressDataset(qryFacturacion_Desglose); 
     spActualizaDesglose.ParamByName('AStream').AsStream := Stream; 
     spActualizaDesglose.ExecProc; 
    end; 

Teraz formularz jest wydany bez problemów, ale czy to prawda?, Czy nie będę mieć wycieku pamięci?

Dziękuję.

+0

Guillot Hi @Marc. Może zobaczę, czy uda mi się odtworzyć ten problem dziś wieczorem. Zanim to zrobię, jaki rozmiar ma strumień "Dane"? Pytam na wypadek, gdy jest to związane z problemami zwracającymi strumień ServerMethods. – MartynA

+0

Wielkie dzięki, Martyn, nie jest to związane z problemem w Datasnapie z dużymi strumieniami. Dzieje się tak zawsze, nawet jeśli istnieje tylko jeden rekord (kilkadziesiąt bajtów). –

+0

Ok, dam mu wir. CU później ... – MartynA

Odpowiedz

7

Od the manual page:

Ustawienie właściwości AsStream ustawia właściwość DataType do ftStream jeśli nie jest to jeden z typów ciągów znaków/bajt smyczkowych/danych BLOB. Przydzielony obiekt TStream będzie własnością tego TFDParam. Aby jawnie kontrolować własność, należy użyć metody SetStream.

Podkreślam moją. Zatem tak, przypisanie strumienia do parametru nadaje własności parametru dla tego strumienia i staje się ono odpowiedzialne za uwolnienie go, gdy samo jest zwalniane (co jest wykonywane przez zbiór danych, gdy jest on zwalniany przez formularz będący właścicielem składnika zbioru danych).

Kiedy uwolnić strumień tutaj:

Stream := CompressDataset(qryFacturacion_Desglose); 
try 
    spActualizaDesglose.ParamByName('AStream').AsStream := Stream; 
    spActualizaDesglose.ExecProc; 
finally 
    Stream.Free; 
end; 

jesteś zniszczenia obiektu, który parametr jest odniesienie do gospodarstwa i podnosi AV gdy obiekt parametr próbuje uwolnić go po raz drugi.

+0

Dziękujemy @J .... –

+1

@J ...: Dobrze zauważony, +1 – MartynA