I use FDQUERY to select a single record from MYSQL that has a blob contining jpg image. Everything functions perfectly as expected.
I added ReportMemoryLeaksOnShutdown:=True to the project DPR. On shutdown I receive the Message:
"An unexpected memory leak has occurred. The unexpected small block leaks are: 1-12 bytes : TStream x 1"
(1 increases for each call to the below line of code.) If I comment out the line there are no memory leaks.
I have tried to trace back through the source code to find the leak but I just can't find it.
Any Help, or workaround would be most appreciated. Many Thanks.
Development Environment is:
Windows 10
Delphi 10.4.2 Pro
MYSQL 8.0.25 (64bit)
MS:=FDQuery1.CreateBlobStream(FDQuery1.FieldbyName('Image'),TBlobStreamMode.bmRead);`
MS Stream Variable IS being freed in a try .. finally block.
Reproducible Code Below:
1 CREATE MYSQL Table Script
CREATE TABLE `TestTable` (
`pk_Id` int NOT NULL AUTO_INCREMENT,
`Image` longblob,
UNIQUE KEY `pk_Id_UNIQUE` (`pk_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=27607 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
2 Delphi Form
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 322
ClientWidth = 720
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 56
Top = 272
Width = 129
Height = 25
Caption = 'Assign Blob To Stream'
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
Left = 512
Top = 40
Width = 137
Height = 25
Caption = 'Insert JPG into Table'
TabOrder = 1
OnClick = Button2Click
end
object FDConnection1: TFDConnection
Params.Strings = (
'Database= INSERT DATABASE NAME HERE' // <-- Change to your MYSQL Database Name
'User_Name= INSERT YOUR USERNAME HERE' // <-- Change to Your MYSQL User name
'Password=INSET YOUR PASSWORD HERE' // <-- Change to Your MYSQL Password
'Server=INSER YOUR SERVER HERE' // <-- Change to Your MYSQL Server Typically 127.0.0.1
'DriverID=MySQL')
Connected = True
LoginPrompt = False
Left = 55
Top = 96
end
object FDGUIxWaitCursor1: TFDGUIxWaitCursor
Provider = 'Forms'
Left = 55
Top = 32
end
object FDQuery1: TFDQuery
Connection = FDConnection1
ResourceOptions.AssignedValues = [rvDirectExecute]
ResourceOptions.DirectExecute = True
SQL.Strings = (
'Select Image from testtable'
''
'')
Left = 56
Top = 166
end
object FDTable1: TFDTable
IndexFieldNames = 'pk_Id'
Connection = FDConnection1
TableName = 'foodforlife.testtable'
Left = 672
Top = 40
end
object FileOpenDialog1: TFileOpenDialog
DefaultExtension = 'jpg'
DefaultFolder = 'C:\'
FavoriteLinks = <>
FileTypes = <
item
DisplayName = ''
FileMask = '*.jpg'
end>
Options = []
Left = 432
Top = 24
end
end
3 Delphi Unit
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MySQL,
FireDAC.Phys.MySQLDef, FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS,
FireDAC.DApt.Intf, FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet,
FireDAC.Comp.Client, FireDAC.Comp.UI, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
FDConnection1: TFDConnection;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDQuery1: TFDQuery;
Button2: TButton;
FDTable1: TFDTable;
FileOpenDialog1: TFileOpenDialog;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
Var
MS : TStream;
begin
MS := TStream.Create;
try
FDQuery1.Active:=True;
MS:=FDQuery1.CreateBlobStream(FDQuery1.FieldbyName('Image'),TBlobStreamMode.bmRead); // --< Memory Leak Here
MS.Position:=0;
finally
ms.Free;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
Var
fs: TFileStream;
begin
If FileOPenDialog1.execute then fs:=TFileStream.Create(FileOPenDialog1.Files[0],fmShareDenyNone);
try
fs.position:=0;
With fdtable1 do
begin
active:=True;
insert;
(FieldByName('Image') as TBlobField).LoadFromStream(fs);
Post
end;
finally
fs.Free;
end;
end;
end.
4 Delphi DPR
program Project1;
uses
Vcl.Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
ReportMemoryLeaksOnShutdown:=True;
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
To Use:
1 Run the Create Script in a MYSQL DB to which you have access
2 Insert the MYSQL DB Paramaters for the table created above in FDConnection1
3 Compile and Run
4 Click Button Titled Insert JPG into Table to display a file open dialog from which you will select a jpg file. When you execute the dialog it will save into the MYSQL table
5 Click the Button Titled Assign Blob to Stream. This will assign the blob to a stream and create the memory leak for every button click