delphi 数据快照内存泄漏

delphi datasnap memory leak

我正在制作 Datasnap 客户端和服务器应用程序的原型。我想将文件从服务器流式传输到客户端。

这是有效的,但我流式传输的每个文件都保留在服务器的内存中。它永远不会被释放,即使我关闭连接/客户端也不会。

我尝试使用:GetInvocationMetaData.CloseSession := True; 在服务器上的方法调用中,但后来我没有得到文件,它是 0 Kb。

我做错了什么?

服务器端代码:(请原谅我的命名) 生命周期是调用

unit ServerMethodsUnitNKDataSnap;

interface

uses System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth,
  Data.DB, IBCustomDataSet, IBQuery, IBDatabase, Datasnap.Provider, DataSnap.DSSession, Data.DBXPlatform;

type
  TServerMethods1 = class(TDSServerModule)
  private
//    FStream:TStream;
  public
    { Public declarations }
    function EchoString(Value: string): string;
    function ReverseString(Value: string): string;
    function DownloadFile(sFile:String): TStream;
    function BestaatFile(sFile:String):Boolean;
    procedure FreeStream;
  end;

implementation

{$R *.dfm}

uses System.StrUtils;

function TServerMethods1.EchoString(Value: string): string;
begin
  Result := Value;
end;

procedure TServerMethods1.FreeStream;
begin
//  FreeAndNil(FStream);
  GetInvocationMetaData.CloseSession := True;
end;

function TServerMethods1.ReverseString(Value: string): string;
begin
  Result := System.StrUtils.ReverseString(Value);
  GetInvocationMetaData.CloseSession := True;
end;

function TServerMethods1.DownloadFile(sFile:String): TStream;
begin
{
  if Assigned(FStream) then
    FreeAndNil(FStream);
  FStream := TFileStream.Create(sFile, fmOpenRead or fmShareDenyNone);

  Result := FStream;
  TFileStream(Result).Seek(0, TSeekOrigin.soBeginning);
}
  result := TFileStream.Create(sFile, fmOpenRead or fmShareDenyNone);
  TFileStream(Result).Seek(0, TSeekOrigin.soBeginning);
//  GetInvocationMetaData.CloseSession := True;
end;

function TServerMethods1.BestaatFile(sFile: string):Boolean;
begin
  Result := FileExists(sFile);
  GetInvocationMetaData.CloseSession := True;
end;

end.

dfm

object ServerContainer2: TServerContainer2
  OldCreateOrder = False
  Height = 271
  Width = 415
  object DSServer1: TDSServer
    Left = 96
    Top = 11
  end
  object DSHTTPService1: TDSHTTPService
    HttpPort = 7070
    Server = DSServer1
    Filters = <>
    Left = 96
    Top = 135
  end
  object DSServerClass1: TDSServerClass
    OnGetClass = DSServerClass1GetClass
    Server = DSServer1
    LifeCycle = 'Invocation'
    Left = 200
    Top = 11
  end
end

客户端代码 生成源

//
// Created by the DataSnap proxy generator.
// 2-2-2015 14:27:21
//

unit ClientClassesUnit1;

interface

uses Datasnap.DSProxyRest, Datasnap.DSClientRest, 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
  TServerMethods1Client = class(TDSAdminRestClient)
  private
    FEchoStringCommand: TDSRestCommand;
    FReverseStringCommand: TDSRestCommand;
    FDownloadFileCommand: TDSRestCommand;
    FDownloadFileCommand_Cache: TDSRestCommand;
    FBestaatFileCommand: TDSRestCommand;
    FFreeStreamCommand: TDSRestCommand;
  public
    constructor Create(ARestConnection: TDSRestConnection); overload;
    constructor Create(ARestConnection: TDSRestConnection; AInstanceOwner: Boolean); overload;
    destructor Destroy; override;
    function EchoString(Value: string; const ARequestFilter: string = ''): string;
    function ReverseString(Value: string; const ARequestFilter: string = ''): string;
    function DownloadFile(sFile: string; const ARequestFilter: string = ''): TStream;
    function DownloadFile_Cache(sFile: string; const ARequestFilter: string = ''): IDSRestCachedStream;
    function BestaatFile(sFile: string; const ARequestFilter: string = ''): Boolean;
    procedure FreeStream;
  end;

const
  TServerMethods1_EchoString: array [0..1] of TDSRestParameterMetaData =
  (
    (Name: 'Value'; Direction: 1; DBXType: 26; TypeName: 'string'),
    (Name: ''; Direction: 4; DBXType: 26; TypeName: 'string')
  );

  TServerMethods1_ReverseString: array [0..1] of TDSRestParameterMetaData =
  (
    (Name: 'Value'; Direction: 1; DBXType: 26; TypeName: 'string'),
    (Name: ''; Direction: 4; DBXType: 26; TypeName: 'string')
  );

  TServerMethods1_DownloadFile: array [0..1] of TDSRestParameterMetaData =
  (
    (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
    (Name: ''; Direction: 4; DBXType: 33; TypeName: 'TStream')
  );

  TServerMethods1_DownloadFile_Cache: array [0..1] of TDSRestParameterMetaData =
  (
    (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
    (Name: ''; Direction: 4; DBXType: 26; TypeName: 'String')
  );

  TServerMethods1_BestaatFile: array [0..1] of TDSRestParameterMetaData =
  (
    (Name: 'sFile'; Direction: 1; DBXType: 26; TypeName: 'string'),
    (Name: ''; Direction: 4; DBXType: 4; TypeName: 'Boolean')
  );

implementation

function TServerMethods1Client.EchoString(Value: string; const ARequestFilter: string): string;
begin
  if FEchoStringCommand = nil then
  begin
    FEchoStringCommand := FConnection.CreateCommand;
    FEchoStringCommand.RequestType := 'GET';
    FEchoStringCommand.Text := 'TServerMethods1.EchoString';
    FEchoStringCommand.Prepare(TServerMethods1_EchoString);
  end;
  FEchoStringCommand.Parameters[0].Value.SetWideString(Value);
  FEchoStringCommand.Execute(ARequestFilter);
  Result := FEchoStringCommand.Parameters[1].Value.GetWideString;
end;

function TServerMethods1Client.ReverseString(Value: string; const ARequestFilter: string): string;
begin
  if FReverseStringCommand = nil then
  begin
    FReverseStringCommand := FConnection.CreateCommand;
    FReverseStringCommand.RequestType := 'GET';
    FReverseStringCommand.Text := 'TServerMethods1.ReverseString';
    FReverseStringCommand.Prepare(TServerMethods1_ReverseString);
  end;
  FReverseStringCommand.Parameters[0].Value.SetWideString(Value);
  FReverseStringCommand.Execute(ARequestFilter);
  Result := FReverseStringCommand.Parameters[1].Value.GetWideString;
end;

function TServerMethods1Client.DownloadFile(sFile: string; const ARequestFilter: string): TStream;
begin
  if FDownloadFileCommand = nil then
  begin
    FDownloadFileCommand := FConnection.CreateCommand;
    FDownloadFileCommand.RequestType := 'GET';
    FDownloadFileCommand.Text := 'TServerMethods1.DownloadFile';
    FDownloadFileCommand.Prepare(TServerMethods1_DownloadFile);
  end;
  FDownloadFileCommand.Parameters[0].Value.SetWideString(sFile);
  FDownloadFileCommand.Execute(ARequestFilter);
  Result := FDownloadFileCommand.Parameters[1].Value.GetStream(FInstanceOwner);
end;

function TServerMethods1Client.DownloadFile_Cache(sFile: string; const ARequestFilter: string): IDSRestCachedStream;
begin
  if FDownloadFileCommand_Cache = nil then
  begin
    FDownloadFileCommand_Cache := FConnection.CreateCommand;
    FDownloadFileCommand_Cache.RequestType := 'GET';
    FDownloadFileCommand_Cache.Text := 'TServerMethods1.DownloadFile';
    FDownloadFileCommand_Cache.Prepare(TServerMethods1_DownloadFile_Cache);
  end;
  FDownloadFileCommand_Cache.Parameters[0].Value.SetWideString(sFile);
  FDownloadFileCommand_Cache.ExecuteCache(ARequestFilter);
  Result := TDSRestCachedStream.Create(FDownloadFileCommand_Cache.Parameters[1].Value.GetString);
end;

function TServerMethods1Client.BestaatFile(sFile: string; const ARequestFilter: string): Boolean;
begin
  if FBestaatFileCommand = nil then
  begin
    FBestaatFileCommand := FConnection.CreateCommand;
    FBestaatFileCommand.RequestType := 'GET';
    FBestaatFileCommand.Text := 'TServerMethods1.BestaatFile';
    FBestaatFileCommand.Prepare(TServerMethods1_BestaatFile);
  end;
  FBestaatFileCommand.Parameters[0].Value.SetWideString(sFile);
  FBestaatFileCommand.Execute(ARequestFilter);
  Result := FBestaatFileCommand.Parameters[1].Value.GetBoolean;
end;

procedure TServerMethods1Client.FreeStream;
begin
  if FFreeStreamCommand = nil then
  begin
    FFreeStreamCommand := FConnection.CreateCommand;
    FFreeStreamCommand.RequestType := 'GET';
    FFreeStreamCommand.Text := 'TServerMethods1.FreeStream';
  end;
  FFreeStreamCommand.Execute;
end;

constructor TServerMethods1Client.Create(ARestConnection: TDSRestConnection);
begin
  inherited Create(ARestConnection);
end;

constructor TServerMethods1Client.Create(ARestConnection: TDSRestConnection; AInstanceOwner: Boolean);
begin
  inherited Create(ARestConnection, AInstanceOwner);
end;

destructor TServerMethods1Client.Destroy;
begin
  FEchoStringCommand.DisposeOf;
  FReverseStringCommand.DisposeOf;
  FDownloadFileCommand.DisposeOf;
  FDownloadFileCommand_Cache.DisposeOf;
  FBestaatFileCommand.DisposeOf;
  FFreeStreamCommand.DisposeOf;
  inherited;
end;

end.

自己的来源

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  Vcl.Grids, Vcl.DBGrids, IPPeerClient, Datasnap.DSClientRest;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Label4: TLabel;
    Button5: TButton;
    Edit5: TEdit;
    Label5: TLabel;
    Edit6: TEdit;
    Label6: TLabel;
    DSRestConnection1: TDSRestConnection;
    procedure Button1Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    procedure DownloadFile(sSourceFile,sTargetFile:string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses ClientClassesUnit1;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var oServerMethodsClient:TServerMethods1Client;
begin
  oServerMethodsClient := nil;
  try
    try
      oServerMethodsClient := TServerMethods1Client.Create(DSRestConnection1, True);
      ShowMessage(oServerMethodsClient.EchoString(edit1.Text));
      ShowMessage(oServerMethodsClient.ReverseString(edit1.Text));
    except
      on E: Exception do
      begin
        showmessage('Oeps echo: ' + E.Message);
      end;
    end;
  finally
    FreeAndNil(oServerMethodsClient);
  end;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  DownloadFile(edit5.Text, edit6.Text);
end;

procedure TForm1.DownloadFile(sSourceFile,sTargetFile:String);
var
    RetStream: TStream;
    fs:TFileStream;
    oServerMethodsClient:TServerMethods1Client;
begin
  oServerMethodsClient := nil;
  RetStream := nil;

  try
    try
      oServerMethodsClient := TServerMethods1Client.Create(DSRestConnection1, True);
      RetStream := oServerMethodsClient.DownloadFile(sSourceFile);
//      oServerMethodsClient.FreeStream;
      fs := TFileStream.Create(sTargetFile, fmCreate);
      try
        if RetStream.Size > 0 then
        begin
          RetStream.Position:=0;
          fs.CopyFrom(RetStream, RetStream.Size);
        end;
      finally
         fs.free;
//         retstream.Free;
      end;

    except
      on E: Exception do
      begin
        showmessage('Oeps download: ' + E.Message);
      end;
    end;

  finally
    FreeAndNil(oServerMethodsClient);
  end;
end;

end.

dfm 来源

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 519
  ClientWidth = 959
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label4: TLabel
    Left = 208
    Top = 48
    Width = 53
    Height = 13
    Caption = 'Echo string'
  end
  object Label5: TLabel
    Left = 208
    Top = 93
    Width = 22
    Height = 13
    Caption = 'van:'
  end
  object Label6: TLabel
    Left = 208
    Top = 123
    Width = 22
    Height = 13
    Caption = 'naar'
  end
  object Button1: TButton
    Left = 16
    Top = 43
    Width = 75
    Height = 25
    Caption = 'echo'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Edit1: TEdit
    Left = 288
    Top = 45
    Width = 274
    Height = 21
    TabOrder = 1
    Text = 'bla'
  end
  object Button5: TButton
    Left = 16
    Top = 88
    Width = 75
    Height = 25
    Caption = 'haal 1 file'
    TabOrder = 2
    OnClick = Button5Click
  end
  object Edit5: TEdit
    Left = 288
    Top = 93
    Width = 274
    Height = 21
    TabOrder = 3
    Text = 'c:\source\temp.zip'
  end
  object Edit6: TEdit
    Left = 288
    Top = 120
    Width = 274
    Height = 21
    TabOrder = 4
    Text = 'c:\temp\temp.zip'
  end
  object DSRestConnection1: TDSRestConnection
    Host = 'localhost'
    Port = 7070
    LoginPrompt = False
    PreserveSessionID = False
    Left = 120
    Top = 16
    UniqueId = '{B4909821-9EF2-42F1-AFFF-58B320C35F75}'
  end
end
DataSnap 服务器方法不正确支持

TStream。支持的类型列表可以在 docwiki 中找到:

Exposing DataSnap Server Methods

在你的情况下使用 TDBXStreamValue 似乎是合适的。