Recent

Author Topic: MEMORY USAGE OF SIMPLE PROGRAM  (Read 4475 times)

heejit

  • Full Member
  • ***
  • Posts: 245
MEMORY USAGE OF SIMPLE PROGRAM
« on: February 19, 2018, 01:21:11 pm »

I am new to Lazaurs/Pascal programming never work
with progrmaming lanaguage where we need to manage the
memory.

I dont understand the usage of memory by this program
it is SQL Browser which connected to Local Postgresql db
and run the sql and show the result in ListView.

When program start it shows 5.5mb memory usage.

When I run sql which return lot of rows memory usage increase
but when run sql which return few rows memory usage will not reduce
where it was.

Can some one look into this code help me find out if there is memory
leak or this is how Lazarus/Pascal program works.

OS : Linux/Ubuntu 16.04 64bit
Lazaurs : 1.8
FPC : 3.0.4

Code: Pascal  [Select][+][-]
  1.  
  2. unit Unit1;
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.     Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  10.     StdCtrls, Grids, ComCtrls, sqldb, pqconnection,
  11.     LCLType{for key code};
  12.  
  13. type
  14.  
  15.     { TForm1 }
  16.  
  17.     TForm1 = class(TForm)
  18.         ListBox1: TListBox;
  19.         ListView1: TListView;
  20.         Memo1: TMemo;
  21.         procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  22.         procedure FormCreate(Sender: TObject);
  23.         procedure Memo1KeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
  24.         procedure show_data_in_list_string_grid(rs: TSQLQuery; StringGrid1: TStringGrid);
  25.         procedure show_data_in_list_view(rs: TSQLQuery; lv: TListView);
  26.         procedure run_sql(sql: string);
  27.     private
  28.         conn: TSQLConnection;
  29.         transaction: TSQLTransaction;
  30.  
  31.     public
  32.  
  33.     end;
  34.  
  35. var
  36.     Form1: TForm1;
  37.  
  38. implementation
  39.  
  40. {$R *.lfm}
  41.  
  42. { TForm1 }
  43.  
  44. procedure TForm1.FormCreate(Sender: TObject);
  45. begin
  46.     self.conn := TPQConnection.Create(self);
  47.     self.conn.DatabaseName := 'dbname';
  48.     self.conn.HostName := '127.0.0.1';
  49.     self.conn.UserName := 'user';
  50.     self.conn.Password := 'password';
  51.     self.conn.Connected := True;
  52.     self.transaction    := TSQLTransaction.Create(self.conn);
  53.     self.conn.Transaction := self.transaction;
  54.     self.Memo1.Clear;
  55. end;
  56.  
  57. procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
  58. begin
  59.     if (ssCtrl in shift) and (key = VK_E) then
  60.     begin
  61.         if (self.Memo1.Lines.Text.Length = 0) then
  62.         begin
  63.             ShowMessage('No SQL provided');
  64.             Exit;
  65.         end;
  66.  
  67.         self.run_sql(self.Memo1.Lines.Text);
  68.  
  69.     end;
  70. end;
  71.  
  72. procedure Tform1.run_sql(sql: string);
  73. var
  74.     rs: TSQLQuery;
  75.     error: string;
  76.     is_ok: boolean;
  77.  
  78. begin
  79.     rs          := TSQLQuery.Create(nil);
  80.     rs.DataBase := self.conn;
  81.     rs.SQL.Text := sql;
  82.     is_ok       := True;
  83.     try
  84.         self.transaction.Active := True;
  85.         rs.Open;
  86.         rs.Last;
  87.     except
  88.         on A: EPQDatabaseError do
  89.         begin
  90.             error := A.Message;
  91.             is_ok := False;
  92.             self.transaction.Active := False;
  93.         end;
  94.     end;
  95.  
  96.     if is_ok = False then
  97.     begin
  98.         ShowMessage('Error :' + error);
  99.         exit;
  100.     end;
  101.     self.show_data_in_list_view(rs, self.ListView1);
  102.     FreeAndNil(rs);
  103. end;
  104.  
  105. procedure Tform1.show_data_in_list_view(rs: TSQLQuery; lv: TListView);
  106. var
  107.     i, j: integer;
  108.     vNewItem: TListItem;
  109.     fc: integer;
  110.  
  111. begin
  112.     lv.BeginUpdate;
  113.  
  114.     lv.Items.Clear;
  115.     lv.Clear;
  116.     lv.Columns.Clear;
  117.     lv.ViewStyle := TViewStyle.vsReport;
  118.     lv.ShowColumnHeaders := True;
  119.  
  120.     fc := rs.FieldCount;
  121.     for i := 0 to fc - 1 do
  122.     begin
  123.         lv.Columns.Add;
  124.         lv.Columns[Lv.ColumnCount - 1].Caption  := rs.Fields[i].FieldName;
  125.         lv.Columns[lv.ColumnCount - 1].AutoSize := True;
  126.     end;
  127.  
  128.  
  129.     rs.First;
  130.     while rs.EOF = False do
  131.     begin
  132.         vNewItem := lv.Items.Add;
  133.         vNewItem.Caption := rs.Fields[0].AsString;
  134.         for j := 1 to fc - 1 do
  135.         begin
  136.             vNewItem.SubItems.Add(rs.Fields[j].AsString);
  137.         end;
  138.         rs.Next;
  139.     end;
  140.     lv.EndUpdate;
  141.  
  142.     self.ListBox1.Items.Add('Record Found : ' + IntToStr(lv.Items.Count));
  143.  
  144. end;
  145.  
  146. procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  147. begin
  148.     conn.Close();
  149. end;
  150.  
  151. end.
  152.  

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #1 on: February 19, 2018, 01:38:55 pm »
Can some one look into this code help me find out if there is memory
leak or this is how Lazarus/Pascal program works.
You can check for a memory leak yourself via:
Project > Project Options > Debugging -> check "Use Heaptrc unit".
After you close your program, you'll get a dialog in which you can see if you have a memory leak.

Looking at your code, the only potential problem I see it in Tform1.run_sql().
It's not a problem if the DB is opened correctly but you should wrap the code after rs := TSQLQuery.Create(nil); also in a try/finally.

Code: Pascal  [Select][+][-]
  1.     rs          := TSQLQuery.Create(nil);
  2.     try
  3.       // rest of the code
  4.     finally
  5.       FreeAndNil(rs);
  6.     end;

Note that sometimes a program will take up more memory during its run. That doesn't necessarily mean there is a leak.

sash

  • Sr. Member
  • ****
  • Posts: 366
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #2 on: February 19, 2018, 01:40:30 pm »
I am new to Lazaurs/Pascal programming never work
with progrmaming lanaguage where we need to manage the
memory.

Not sure (tl-dr) if it is exactly your case, but I noticed a potential memory leak:

Code: Pascal  [Select][+][-]
  1. var
  2.   rs: TSQLQuery;
  3. begin
  4.   rs := TSQLQuery.Create(nil);
  5.   // .....
  6.   exit;
  7.   // ......
  8.   FreeAndNil(rs);
  9. end;
  10.  

You should either
 - use try-finally block or
 - declare and create rs: TSQLQuery; in forms' scope (with Form1 as Owner) or
   -- even more simple and convenient: to visually place a TSQLQuery component on form.
« Last Edit: February 19, 2018, 02:44:45 pm by sash »
Lazarus 2.0.10 FPC 3.2.0 x86_64-linux-gtk2 @ Ubuntu 20.04 XFCE

heejit

  • Full Member
  • ***
  • Posts: 245
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #3 on: February 19, 2018, 01:48:43 pm »
Thanks Corrected

Code: Pascal  [Select][+][-]
  1. procedure Tform1.run_sql(sql: string);
  2. var
  3.     rs: TSQLQuery;
  4.     error: string;
  5.     is_ok: boolean;
  6.  
  7. begin
  8.     try
  9.         rs := TSQLQuery.Create(nil);
  10.         rs.DataBase := self.conn;
  11.         rs.SQL.Text := sql;
  12.         is_ok := True;
  13.         try
  14.             self.transaction.Active := True;
  15.             rs.Open;
  16.             rs.Last;
  17.         except
  18.             on A: EPQDatabaseError do
  19.             begin
  20.                 error := A.Message;
  21.                 is_ok := False;
  22.                 self.transaction.Active := False;
  23.             end;
  24.         end;
  25.  
  26.         if is_ok = False then
  27.         begin
  28.             ShowMessage('Error :' + error);
  29.             exit;
  30.         end;
  31.         self.show_data_in_list_view(rs, self.ListView1);
  32.     finally
  33.         FreeAndNil(rs);
  34.     end;
  35.  
  36. end;
  37.  
  38.  

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #4 on: February 19, 2018, 01:50:52 pm »
Normally, you'll put the rs := TSQLQuery.Create(nil); above the try :D
TSQLQuery.Create can't really go wrong so can't give an exception.
So only the code below it needs to be in the try/finally section.

heejit

  • Full Member
  • ***
  • Posts: 245
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #5 on: February 19, 2018, 01:54:21 pm »
ok done

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #6 on: February 19, 2018, 02:00:22 pm »
Not enough: you are debugging, so don't use FreeAndNil, but rs.free
Reason: you just destroyed your stacktrace. In general FreeAndNil is a shortcut to prevent finding bugs, not actually finding them....
Specialize a type, not a var.

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #7 on: February 19, 2018, 02:10:01 pm »
Normally, you'll put the rs := TSQLQuery.Create(nil); above the try :D
TSQLQuery.Create can't really go wrong so can't give an exception.
So only the code below it needs to be in the try/finally section.
OMG: EOutOfMemory.... for one... You are not very helpful today. Usually you are.
You are on the spot about try finally, btw. of course.
« Last Edit: February 19, 2018, 02:12:19 pm by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #8 on: February 19, 2018, 02:11:08 pm »
Normally, you'll put the rs := TSQLQuery.Create(nil); above the try :D
TSQLQuery.Create can't really go wrong so can't give an exception.
So only the code below it needs to be in the try/finally section.
OMG: EOutOfMemory.... for one...
Why? Would you put the rs := TSQLQuery.Create(nil); inside the try/finally (like jshah did in the correction)??

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #9 on: February 19, 2018, 02:13:45 pm »
No, but it would show up in a proper stacktrace. FreeAndNil will remove that stacktrace.... try it.
(I knew because I was building more "defensive programming"  examples)
« Last Edit: February 19, 2018, 02:15:46 pm by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #10 on: February 19, 2018, 02:15:50 pm »
No, but it would show up in a proper stacktrace. FreeAndNil will remove that stacktrace.... try it.
O, no, I agree with you on the FreeAndNil. Never, ever use that, if you don't use the variable again. And even then, you should only use it wisely and know what you are doing.

Thaddy

  • Hero Member
  • *****
  • Posts: 14198
  • Probably until I exterminate Putin.
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #11 on: February 19, 2018, 02:34:19 pm »
Even sour grapes contain sugar...
Point of note is YOU (assume) code to never be used. What if you are pushing up daisies?
« Last Edit: February 19, 2018, 02:36:33 pm by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6110
Re: MEMORY USAGE OF SIMPLE PROGRAM
« Reply #12 on: February 19, 2018, 02:40:37 pm »
Point of note is YOU (assume) code to never be used. What if you are pushing up daisies?
Not sure if that was directed at me? I agreed with you, that you shouldn't use FreeAndNil(). Or if you even read my comment properly?

In this case I would:
Code: Pascal  [Select][+][-]
  1. rs := TSQLQuery.Create(nil);
  2. try
  3.   // code
  4. finally
  5.   rs.Free;
  6. end;

 

TinyPortal © 2005-2018