Recent

Author Topic: [bug]EasyLazFreeType waste much memory  (Read 3170 times)

mercury

  • Full Member
  • ***
  • Posts: 154
[bug]EasyLazFreeType waste much memory
« on: March 23, 2017, 04:14:33 am »
While render text with BGRABitmap by function TBGRAFreeTypeFontRenderer.TextSize. A critical memory leak waste occur. It seems because of code:
    result.cx := round(FFont.TextWidth(s));
Which comes from TFreeTypeFont.TextWidth in unit EasyLazFreeType.
I can’t find exact leak point, Heaptrc is not helping.
Please fix this.
« Last Edit: March 26, 2017, 08:55:31 am by mercury »

mercury

  • Full Member
  • ***
  • Posts: 154
Re: EasyLazFreeType memory leak
« Reply #1 on: March 23, 2017, 03:06:42 pm »
Screenshot and source code attached

Source code: project1.7z
SIZE   : 5915021
MD5    : 4d3a76110170907c591ac3e8fdf30664
SHA1   : b1b7e8b3c2fd60f87094693b66eec5b319cdcac6
http://uppit.com/ct47w3rjw6j2

see the following reply
(I hope forum’s maximum upload size can be bigger, 250KB is too small.)
« Last Edit: March 24, 2017, 04:20:03 am by mercury »

Thaddy

  • Hero Member
  • *****
  • Posts: 14159
  • Probably until I exterminate Putin.
Re: EasyLazFreeType memory leak
« Reply #2 on: March 23, 2017, 05:16:13 pm »
Why would that be too small?
- You can reduce the size of the image
- You should not include any binaries, just sourcecode.
- Provide a link to the font, but don't include it.
- Don't use Uppit. Use a public documents folder on Google Drive or Onedrive.
- See screenshot why I am not going to put any effort in..
« Last Edit: March 23, 2017, 05:44:26 pm by Thaddy »
Specialize a type, not a var.

mercury

  • Full Member
  • ***
  • Posts: 154
Re: EasyLazFreeType memory leak
« Reply #3 on: March 24, 2017, 04:07:25 am »
You can reduce the size of the image
A 25.42 kB image is not big. A 10MB ttf is not big too.

You should not include any binaries, just sourcecode.
project1.7z is not include any binaries.

Provide a link to the font, but don't include it.
It is NotoSansCJK-Regular but convert to ttf, because LazFreeType seems do not support otf.
Other font may reproduce this bug too.

Don't use Uppit. Use a public documents folder on Google Drive or Onedrive.
Did you know that Google Drive or Onedrive both can not be accessed in China.

See screenshot why I am not going to put any effort in..
Sorry, I only test the download on Firefox. Could you recommend another file share service?

mercury

  • Full Member
  • ***
  • Posts: 154
Re: EasyLazFreeType memory leak
« Reply #4 on: March 24, 2017, 04:07:55 am »
part 2 attached

unit1.pas :
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, LCLProc, Forms, Controls, Graphics, Dialogs, ExtCtrls,
  9.   BGRABitmap, BGRAFreeType, BGRABitmapTypes, BGRAGraphics;
  10.  
  11. type
  12.   TFont = class(TBGRAFreeTypeFontRenderer)
  13.   private
  14.     function GetAscent: single;
  15.     function GetDescent: single;
  16.     function GetLineSpacing: single;
  17.     function GetLineFullHeight: single;
  18.   protected
  19.   public
  20.     property Name: string read FontName;
  21.     property Height: integer read FontEmHeight write FontEmHeight;
  22.     property Style: TFontStyles read FontStyle write FontStyle;
  23.     property Quality: TBGRAFontQuality read FontQuality write FontQuality;
  24.     property Orientation: integer read FontOrientation write FontOrientation;
  25.  
  26.     property Ascent: single read GetAscent;
  27.     property Descent: single read GetDescent;
  28.     property LineSpacing: single read GetLineSpacing;
  29.     property LineFullHeight: single read GetLineFullHeight;
  30.  
  31.     constructor Create();
  32.     constructor Create(AFilename: string);
  33.  
  34.     function LoadFont(const Filename: string): integer;
  35.  
  36.   end;
  37.  
  38.   { TForm1 }
  39.  
  40.   TForm1 = class(TForm)
  41.     Timer1: TTimer;
  42.     procedure FormCreate(Sender: TObject);
  43.     procedure FormDestroy(Sender: TObject);
  44.     procedure FormPaint(Sender: TObject);
  45.     procedure Timer1Timer(Sender: TObject);
  46.   private
  47.     { private declarations }
  48.   public
  49.     { public declarations }
  50.   end;
  51.  
  52. var
  53.   Form1: TForm1;
  54.   Count: integer = 0;
  55.   AFont: TFont;
  56.   ABGRABitmap: TBGRABitmap;
  57.  
  58. implementation
  59.  
  60. { TFont }
  61.  
  62. function TFont.GetAscent: single;
  63. begin
  64.   Result := FFont.Ascent;
  65.   //OutputLn('FFont.SizeInPixels : ' + FloatToStr(FFont.SizeInPixels));
  66.   //OutputLn('FFont.SizeInPoints : ' + FloatToStr(FFont.SizeInPoints));
  67. end;
  68.  
  69. function TFont.GetDescent: single;
  70. begin
  71.   Result := FFont.Descent;
  72. end;
  73.  
  74. function TFont.GetLineSpacing: single;
  75. begin
  76.   Result := FFont.LineSpacing;
  77. end;
  78.  
  79. function TFont.GetLineFullHeight: single;
  80. begin
  81.   Result := FFont.LineFullHeight;
  82. end;
  83.  
  84. constructor TFont.Create();
  85. begin
  86.   inherited;
  87. end;
  88.  
  89. constructor TFont.Create(AFilename: string);
  90. begin
  91.   inherited Create;
  92.  
  93.   LoadFont(AFilename);
  94.  
  95.   FontEmHeight := 50;
  96.   FontStyle := [];
  97.   FontQuality := fqFineAntialiasing;
  98.   // FontOrientation := 0; // BGRABitmap 暂不支持此属性
  99.   // FFont.Style := [ftsBold, ftsItalic];
  100. end;
  101.  
  102. function TFont.LoadFont(const Filename: string): integer;
  103. var
  104.   Stream: TFileStream;
  105. begin
  106.   try
  107.     Stream := TFileStream.Create(Filename, fmOpenRead);
  108.     FFont.AccessFromStream(Stream, True);
  109.   except
  110.     on E: Exception do begin
  111.       DebugLn('Error: ' + E.UnitName + '/' + E.ClassName + ' : ' + E.Message);
  112.       Exit(-1);
  113.     end;
  114.   end;
  115.   Result := 0;
  116. end;
  117.  
  118. {$R *.lfm}
  119.  
  120. { TForm1 }
  121.  
  122. procedure TForm1.FormCreate(Sender: TObject);
  123. begin
  124.   AFont := TFont.Create;
  125.   with AFont do begin
  126.     LoadFont('NotoSansCJK-Regular.ttf');
  127.  
  128.     FontEmHeight := 30;
  129.     FontStyle := [];
  130.     FontQuality := fqFineAntialiasing;
  131.   end;
  132.  
  133.   ABGRABitmap := TBGRABitmap.Create(500, 500);
  134. end;
  135.  
  136. procedure TForm1.FormDestroy(Sender: TObject);
  137. begin
  138.   AFont.Free;
  139.   ABGRABitmap.Free;
  140. end;
  141.  
  142. procedure TForm1.FormPaint(Sender: TObject);
  143. var
  144.   ARect: TRect;
  145. begin
  146.   ARect := Rect(0, 0, 500, 500);
  147.   Form1.Canvas.CopyRect(ARect, ABGRABitmap.Bitmap.Canvas, ARect);
  148. end;
  149.  
  150. procedure TForm1.Timer1Timer(Sender: TObject);
  151. begin
  152.   Count += 1;
  153.   ABGRABitmap.FillTransparent;
  154.   AFont.TextSize('abcdefg1234567内存泄漏!' + IntToStr(Count));
  155.   AFont.TextOut(ABGRABitmap, 0, 0,
  156.     'abcdefg1234567内存泄漏!' + IntToStr(Count), BGRABlack, taLeftJustify);
  157.   Form1.Invalidate;
  158. end;
  159.  
  160. end.
  161.  
  162.  
« Last Edit: March 24, 2017, 04:11:21 am by mercury »

mercury

  • Full Member
  • ***
  • Posts: 154
Re: EasyLazFreeType memory leak
« Reply #5 on: March 26, 2017, 05:48:48 am »
I might find the problem. It's not memory leak, but do keep wasting memory.
In unit “easylazfreetype” function:
Code: Pascal  [Select][+][-]
  1. function TFreeTypeFont.GetGlyph(Index: integer): TFreeTypeGlyph;
  2. var node: TAvgLvlTreeNode;
  3.     lGlyph: TFreeTypeGlyph;
  4. begin
  5.   if not CheckInstance then
  6.   begin
  7.     result := nil;
  8.     exit;
  9.   end;
  10.   node := FindGlyphNode(Index);
  11.   if node = nil then
  12.   begin
  13.     lGlyph := TFreeTypeGlyph.Create(self, Index);;
  14.     FGlyphTable.Add(lGlyph);
  15.   end else
  16.     lGlyph := TFreeTypeGlyph(node.Data);
  17.   result := lGlyph;
  18. end;
FindGlyphNode cannot result an accuracy value. So it keep doing “FGlyphTable.Add(lGlyph);”. That’s the problem.

Any idea how to fix this?

mercury

  • Full Member
  • ***
  • Posts: 154
Re: [bug]EasyLazFreeType waste much memory
« Reply #6 on: August 17, 2017, 06:12:10 am »
I think this should fix it.

code
Code: Pascal  [Select][+][-]
  1. function TFreeTypeFont.FindGlyphNode(Index: Integer): TAvgLvlTreeNode;
  2. var DataValue: integer;
  3. begin
  4.   Result:=FGlyphTable.Root;
  5.   while (Result<>nil) do begin
  6.     DataValue := TFreeTypeGlyph(Result.Data).Index;
  7.     if Index=DataValue then exit;
  8.     if Index<DataValue then begin
  9.       Result:=Result.Left
  10.     end else begin
  11.       Result:=Result.Right
  12.     end;
  13.   end;
  14. end;

should be
Code: Pascal  [Select][+][-]
  1. function TFreeTypeFont.FindGlyphNode(Index: Integer): TAvgLvlTreeNode;
  2. var DataValue: integer;
  3. begin
  4.   Result:=FGlyphTable.FindLowest;
  5.   while (Result<>nil) do begin
  6.     DataValue := TFreeTypeGlyph(Result.Data).Index;
  7.     if Index=DataValue then exit;
  8.     Result:=Result.Successor;
  9.   end;
  10. end;

Don't know how freepascal's svn works, please merge the patch.

circular

  • Hero Member
  • *****
  • Posts: 4181
    • Personal webpage
Re: [bug]EasyLazFreeType waste much memory
« Reply #7 on: April 16, 2020, 11:55:41 am »
What was missing was the compare function.

This has been fixed recently:
https://bugs.freepascal.org/view.php?id=35627
Conscience is the debugger of the mind

 

TinyPortal © 2005-2018