Autor Beitrag
umpani
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 389



BeitragVerfasst: Mi 22.10.08 23:26 
Hallo zusammen,

ich habe versuche jetzt schon mehrere Tage lang ein Memory Leak herauszufinden. Aber nichts klappt bis jetzt.
Ich schreibe ein Programm, das mit anderen Torrent-Clients kommunizieren soll. Dafür werden die einzelnen TCP-Packete in Stream bereitsgestellt und über die Socket-komponente verschickt. Klappt auch alles. Allerdings verbraucht das Programm immer mehr Speicher. Mittels FastMM4 habe ich jetzt einige Problemstellen herausgefunden. Aber eine Lösung habe ich noch nicht gefunden. Wenn ich übrigens das Programm minimiere und wieder maximiere ist der unnötige Speicherbereich wieder freigegeben (natürlich nur um dann direkt wieder zu wachsen),

Hier ist z.B. ein Auszug aus der FastMM Log Datei. An der Stelle, die FastMM bezeichet, erstellt dasProgramm einen Torrent-Handshake und versendet diese zu einem TCPServer.
ausblenden volle Höhe Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
A memory block has been leaked. The size is: 8356

This block was allocated by thread 0xD18, and the stack trace (return addresses) at the time was:
402EE2 [system.pas][System][@GetMem][2648]
4241CF [classes.pas][Classes][TMemoryStream.SetCapacity][5591]
424335 [classes.pas][Classes][TMemoryStream.Write][5639]
4C698A [sendestreams.pas][sendestreams][get_handshake][45]
4C7C2C [peerconnect.pas][peerconnect][TPeerconnect.torrent_verbindung_aufbauen][467]
4C7B2D [peerconnect.pas][peerconnect][TPeerconnect.Execute][410]
42A985 [classes.pas][Classes][ThreadProc][9866]
404A7E [system.pas][System][ThreadWrapper][12127]
7C80B683 [Unknown function at GetModuleFileNameA]

The block is currently used for an object of class: Unknown

The allocation number is: 87562

Current memory dump of 256 bytes starting at pointer address 7FBE41F0:
13 42 69 74 54 6F 72 72 65 6E 74 20 70 72 6F 74 6F 63 6F 6C 00 00 00 00 00 00 00 00 87 69 7F 14
D6 F5 33 9C BC FE 57 70 E3 50 0D 5D 0B 7D 8C FB 41 5A 32 35 30 30 42 54 30 30 30 30 30 30 30 30
30 30 30 30 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
.  B  i  t  T  o  r  r  e  n  t     p  r  o  t  o  c  o  l  .  .  .  .  .  .  .  .  ‡  i    .
Ö  õ  3  µ  Ÿ  þ  W  p  ã  P  .  ]  .  }  ©  û  A  Z  2  5  0  0  B  T  0  0  0  0  0  0  0  0
0  0  0  0  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €
€  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €
€  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €
€  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €
€  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €
€  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €


Der dazugehörige Delphi-Code:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  try
     torrent.peers.peerliste[peernr].client.Socket.SendStream(get_handshake(torrent));
  finally
  ...
  end;


ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
function get_handshake(input:ttorrent):tstream;
  var
      pstrlen:byte;
      pstr:string;
      reserved:integer;
      infohashhex:string[40];
      infohash:array[1..20of byte;
      peer_id:string[20];
      i,int:integer;
      s:string;

begin
  result := tmemorystream.create;
  infohashhex := input.infohashhex;
  infohashhex := uppercase(infohashhex);
  for i := 1 to 20 do
    begin
      s := '';
      s := s + infohashhex[i*2-1];
      s := s + infohashhex[i*2];
      infohash [i] := hextoint(s);
    end;

    pstrlen := 19;
    result.Write(pstrlen,1);
    pstr := 'BitTorrent protocol';

    schreibe_string_in_stream(result,pstr);

    reserved := 0;
    result.Write(reserved,sizeof(reserved));
    result.Write(reserved,sizeof(reserved));

    result.Write(infohash,20);

    peer_id := 'AZ2500BT000000000000';
    schreibe_string_in_stream(result,peer_id);

    result.Seek(0,soFromBeginning);
end;


In den Delphihilfen steht, das "socket.sendstream" den übegebenen Stream selbst freigibt. Eine eigenhändige Freigabe verursacht eine exception.

Wie gesagt, von der Funktion her funktionieren der Code einwandfrei.

Ich hoffe ihr könnt mir weiterhelfen.

Gruß Umpani

_________________
Lernen, ohne zu denken, ist eitel; denken, ohne zu lernen, ist gefährlich. Konfuzius
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Mi 22.10.08 23:47 
Du könntest damit anfangen, den MemoryStream wieder freizugeben, indem du ihn zumindest irgendwo zwischenspeicherst.

Edit: Die Art, wie du das da machst, find ich sowieso etwas unschön.
Besser wäre, du erzeugst den MemoryStream in der aufrufenden Funktion und übergibst ihn dann als Parameter.

_________________
PROGRAMMER: A device for converting coffee into software.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10185
Erhaltene Danke: 1261

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 23.10.08 01:50 
Moin!

user profile iconumpani hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
torrent.peers.peerliste[peernr].client.Socket.SendStream(get_handshake(torrent));					
Du beachtest, dass die Methode TClientSocket.Socket.SendStream() Eigentümer des Streams wird?

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
umpani Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 389



BeitragVerfasst: Do 23.10.08 07:47 
Ersteinmal danke für die schnellen Antworten.

1. @Xentar
Zitat:
Du könntest damit anfangen, den MemoryStream wieder freizugeben, indem du ihn zumindest irgendwo zwischenspeicherst.


Das Verstehe ich nicht so ganz, das erläutern?

2. @Xentar
Zitat:

Edit: Die Art, wie du das da machst, find ich sowieso etwas unschön.
Besser wäre, du erzeugst den MemoryStream in der aufrufenden Funktion und übergibst ihn dann als Parameter.


Ich weiß, so wie du das schilderst hatte ich das auch am Anfang. Hatte aber keine Auswirkungen auf das Speicherproblem. Ich habe dann etwas experimentiert, wie es noch anders geht.

3. @Narses
Zitat:

Du beachtest, dass die Methode TClientSocket.Socket.SendStream() Eigentümer des Streams wird?


Ja das war mir bekannt. Ich benötige den Stream im weitreren Verlauf auch nicht mehr. Er soll lediglich über die Socket Komponente weggeschickt werden. Angeblich soll die Komponente ihn nach dem versenden auch weider freigeben.

_________________
Lernen, ohne zu denken, ist eitel; denken, ohne zu lernen, ist gefährlich. Konfuzius
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Do 23.10.08 09:08 
Ähm.. nein.
Das wär ja schlimm, wenn die Methode SendStream() automatisch den übergebenen Stream freigibt. Was wäre, wenn man den danach noch braucht?
Da muss man sich schon selber drum kümmern.

Was ich halt meinte:
Möglichkeit 1
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
MyStream := get_handshake(torrent);
try
  torrent.peers.peerliste[peernr].client.Socket.SendStream(MyStream);
finally
  MyStream.Free;
end;

unschön, aber wär schonmal ein Fortschritt.

Besser:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
MyStream := TMemoryStream.create;
try
  get_handshake(torrent, MyStream);
  torrent.peers.peerliste[peernr].client.Socket.SendStream(MyStream);
finally
  FreeAndNil(MyStream);
end;

Du übergibst der Funktion also den Stream, wo sie reinschreiben soll. Hierbei musst du dann natürlich das Create rausnehmen.

_________________
PROGRAMMER: A device for converting coffee into software.
umpani Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 389



BeitragVerfasst: Do 23.10.08 09:13 
Das hatte ich auch schon versucht, aber das gibt ne Exception.

heir ein Auszug aus der entsprechenden Delphi Hilfe für SendStream:
Zitat:

Hinweis:
Eigentümer des Stream, der als Parameter an SendStream übergeben wird, wird das Windows-Socket-Objekt. Das Windows-Socket-Objekt gibt den Stream nach erfolgter Verarbeitung frei. Versuchen Sie nicht, den Stream, nachdem er als Parameter übergeben wurde, freizugeben.


Wenn ich das richtig lese, darf ich den Stream also selber nicht freigeben.

_________________
Lernen, ohne zu denken, ist eitel; denken, ohne zu lernen, ist gefährlich. Konfuzius
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Do 23.10.08 09:20 
Doh, das wusste ich nicht (und habs in deinem ersten Beitrag überlesen).

_________________
PROGRAMMER: A device for converting coffee into software.