Disadvantages of Delphi XE8 leak into a simple client and server DataSnap application

I created a simple client / server DataSnap application with a wizard in Delphi XE8, using echo stream selection and reverse methods. When I put "ReportMemoryLeaksOnShutdown: = True" in the dpr server and calling the echo and / or reverse methods from the client, the result is good, but when I close the server application (after closing the client), I always get 2 or more unknown memory leaks. Is this a known bug that I cannot find on the Internet or is there a solution?

Server Code:

unit ServerMethodsUnit; interface uses System.SysUtils, System.Classes, System.Json, Datasnap.DSServer, Datasnap.DSAuth, DataSnap.DSProviderDataModuleAdapter; type {$METHODINFO ON} TServerMethods = class(TDataModule) private { Private declarations } public { Public declarations } function EchoString(Value: string): string; function ReverseString(Value: string): string; end; {$METHODINFO OFF} implementation {%CLASSGROUP 'FMX.Controls.TControl'} {$R *.dfm} uses System.StrUtils; function TServerMethods.EchoString(Value: string): string; begin Result := Value; end; function TServerMethods.ReverseString(Value: string): string; begin Result := System.StrUtils.ReverseString(Value); end; end. 

Dfm

 object ServerContainer: TServerContainer OldCreateOrder = False Height = 271 Width = 415 object DSServer1: TDSServer Left = 96 Top = 11 end object DSTCPServerTransport1: TDSTCPServerTransport Server = DSServer1 Filters = <> Left = 96 Top = 73 end object DSServerClass1: TDSServerClass OnGetClass = DSServerClass1GetClass Server = DSServer1 Left = 200 Top = 11 end end 

Dfm project file

 program DataSnap_Server; uses FMX.Forms, Web.WebReq, IdHTTPWebBrokerBridge, ServerMainForm in 'ServerMainForm.pas' {Form2}, ServerMethodsUnit in 'ServerMethodsUnit.pas' {ServerMethods: TDataModule}, ServerContainerUnit in 'ServerContainerUnit.pas' {ServerContainer: TDataModule}; {$R *.res} begin ReportMemoryLeaksOnShutdown := True; Application.Initialize; Application.CreateForm(TForm2, Form2); Application.CreateForm(TServerContainer, ServerContainer); Application.Run; end. 

client code generated source code

 // // Created by the DataSnap proxy generator. // 14-5-2015 22:45:56 // unit ClientClassesUnit; interface uses System.JSON, Data.DBXCommon, Data.DBXClient, Data.DBXDataSnap, Data.DBXJSON, Datasnap.DSProxy, System.Classes, System.SysUtils, Data.DB, Data.SqlExpr, Data.DBXDBReaders, Data.DBXCDSReaders, Data.DBXJSONReflect; type TServerMethodsClient = class(TDSAdminClient) private FEchoStringCommand: TDBXCommand; FReverseStringCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection); overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function EchoString(Value: string): string; function ReverseString(Value: string): string; end; implementation function TServerMethodsClient.EchoString(Value: string): string; begin if FEchoStringCommand = nil then begin FEchoStringCommand := FDBXConnection.CreateCommand; FEchoStringCommand.CommandType := TDBXCommandTypes.DSServerMethod; FEchoStringCommand.Text := 'TServerMethods.EchoString'; FEchoStringCommand.Prepare; end; FEchoStringCommand.Parameters[0].Value.SetWideString(Value); FEchoStringCommand.ExecuteUpdate; Result := FEchoStringCommand.Parameters[1].Value.GetWideString; end; function TServerMethodsClient.ReverseString(Value: string): string; begin if FReverseStringCommand = nil then begin FReverseStringCommand := FDBXConnection.CreateCommand; FReverseStringCommand.CommandType := TDBXCommandTypes.DSServerMethod; FReverseStringCommand.Text := 'TServerMethods.ReverseString'; FReverseStringCommand.Prepare; end; FReverseStringCommand.Parameters[0].Value.SetWideString(Value); FReverseStringCommand.ExecuteUpdate; Result := FReverseStringCommand.Parameters[1].Value.GetWideString; end; constructor TServerMethodsClient.Create(ADBXConnection: TDBXConnection); begin inherited Create(ADBXConnection); end; constructor TServerMethodsClient.Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); begin inherited Create(ADBXConnection, AInstanceOwner); end; destructor TServerMethodsClient.Destroy; begin FEchoStringCommand.DisposeOf; FReverseStringCommand.DisposeOf; inherited; end; end. 

Own source

 unit ClientMainForm; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; Button2: TButton; Label1: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} uses ClientModuleUnit; procedure TForm1.Button1Click(Sender: TObject); begin Label1.Caption := ClientModule.ServerMethodsClient.EchoString(Edit1.Text); end; procedure TForm1.Button2Click(Sender: TObject); begin Label1.Caption := ClientModule.ServerMethodsClient.ReverseString(Edit1.Text); end; end. 
+6
source share
2 answers

A memory leak looks like it always exists, or we are doing something wrong.

What I checked:

I move all the server application code into one block. I am trying a server application without FMX - with VCL. I am trying to create TDSServer, TDSTCPServerTransport, TDSServerClass at runtime with parents Self and Nil. I am trying with the class owner TServerMethod TPersistance and TComponent (Delphi help says to use it). I am trying to compile a server application as a 32-bit and 64-bit application in Delphi XE7 Update 1 and in Delphi XE8.

EurekaLog 7.2.2 also cannot catch memory leak information. To avoid blocking access to EurekaLog access violation, you must use DSServer1.Stop before exiting.

As we have seen, the access violation occurs when you use EurekaLog there are mainly in System.TObject.InheritsFrom (???) System._IsClass ($ 64AE4E0, TDSServerTransport) Datasnap.DSCommonServer.TDSCustomServer.StopTransports Datasnap.DSCommonServer.TDSCustomServer.Stop Datasnap .DSServer.TDSServer.Stop Datasnap.DSServer.TDSServer.Destroy System.TObject.Free System.Classes.TComponent.DestroyComponents System.Classes.TComponent.Destroy System.Classes.TDataModule.Destroy System.TObject.Free System.Classes.TCompon. DestroyComponents FMX.Forms.DoneApplication System.SysUtils.DoExitProc System._Halt0: 00408da8 TObject.InheritsFrom + $ 8

Server application:

 unit ufmMain; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Datasnap.DSServer, Datasnap.DSTCPServerTransport, Datasnap.DSAuth, DataSnap.DSProviderDataModuleAdapter, Datasnap.DSCommonServer, IPPeerServer; type {$METHODINFO ON} TServerMethods = class(TComponent) private { Private declarations } public { Public declarations } function EchoString(Value: string): string; end; {$METHODINFO OFF} TfmMain = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } DSServer1: TDSServer; DSTCPServerTransport1: TDSTCPServerTransport; DSServerClass1: TDSServerClass; procedure DSServerClass1GetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); end; var fmMain: TfmMain; implementation {$R *.dfm} uses System.StrUtils; function TServerMethods.EchoString(Value: string): string; begin Result := Value; end; procedure TfmMain.DSServerClass1GetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass); begin PersistentClass := TServerMethods; end; procedure TfmMain.FormCreate(Sender: TObject); begin DSServer1 := TDSServer.Create(nil); DSServer1.Name := 'DSServer1'; DSServer1.AutoStart := False; DSTCPServerTransport1 := TDSTCPServerTransport.Create(nil); DSTCPServerTransport1.Server := DSServer1; DSServerClass1 := TDSServerClass.Create(nil); DSServerClass1.Server := DSServer1; DSServerClass1.OnGetClass := DSServerClass1GetClass; DSServer1.Start; end; procedure TfmMain.FormDestroy(Sender: TObject); begin DSServer1.Stop; DSServerClass1.Free; DSTCPServerTransport1.Free; DSServer1.Free; end; end. 
0
source

I assume this is already a known bug for XE8, I think it is quite serious, at least serious enough so that we DO NOT use XE8 before Embarcadero gives us an answer to what is happening. We had a similar problem in XE2, as far as I remember, it was with heavy callbacks.

This Eurekalog doesn't tell me much, it looks deep inside the datasnap, sorry, I don’t know how to make the magazine more readable.

EDIT: I reported this issue to Embarcadero and received this answer today:

// Hello Henrik,

Some of the memory leaks are related to an error in System.Collections.Generics.pas, we are considering the release of a fix for this problem in the near future.

brgds

Roy. //

Thought you wanna know :)

0
source

Source: https://habr.com/ru/post/987234/


All Articles