Einzelnen Beitrag anzeigen

Rollo62

Registriert seit: 15. Mär 2007
4.094 Beiträge
 
Delphi 12 Athens
 
#1

[ARC] Clipper Arrayübergabe hat MemoryLeaks

  Alt 24. Mai 2016, 20:42
Hallo zusammen,

ich versucher gerade die Clipper Library von Angus Johnson
auf Fmx und Mobile zu adaptieren.
Da bekomme ich aber noch so unschöne MemoryLeaks, die man leider schlecht verifizieren kann.

Soweit hatte ich diese Klasse ausgemacht, wo Arrays und ArryOfArry benutzt wird um die Child-Knoten zu speichern.

Delphi-Quellcode:
  TPolyNode = class;
  TArrayOfPolyNode = array of TPolyNode;

  TPolyNode = class
  private
    FPath : TPath;
    FParent : TPolyNode;
    FIndex : Integer;
    FCount : Integer;
    FBuffLen : Integer;
    FIsOpen : Boolean;
    FChilds : TArrayOfPolyNode;
    FJoinType: TJoinType; //used by ClipperOffset only
    FEndType : TEndType; //used by ClipperOffset only
    function GetChild(Index: Integer): TPolyNode;
    function IsHoleNode: boolean;
    procedure AddChild(PolyNode: TPolyNode);
    function GetNextSiblingUp: TPolyNode;
  public
    function GetNext: TPolyNode;
    property ChildCount: Integer read FCount;
    property Childs[index: Integer]: TPolyNode read GetChild;
    property Parent: TPolyNode read FParent;
    property IsHole: Boolean read IsHoleNode;
    property IsOpen: Boolean read FIsOpen;
    property Contour: TPath read FPath;
  end;

function TPolyNode.GetChild(Index: Integer): TPolyNode;
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.Create('TPolyNode range error: ' + inttostr(Index));
  Result := FChilds[Index];
end;


procedure TPolyNode.AddChild(PolyNode: TPolyNode);
begin
  if FCount = FBuffLen then
  begin
    Inc(FBuffLen, 16);
    SetLength(FChilds, FBuffLen);
  end;
  PolyNode.FParent := self;
  PolyNode.FIndex := FCount;
  FChilds[FCount] := PolyNode; //<-- Hier vermute ich das eine Referenz übergeben wird, und nicht wieder freigegeben wird
  Inc(FCount);
end;
Benutzt wird es dann z.B. hier
Delphi-Quellcode:
procedure TClipperOffset.AddPath(const Path: TPath;
  JoinType: TJoinType; EndType: TEndType);
var
  I, J, K, HighI: Integer;
  NewNode: TPolyNode;
  ip: TIntPoint;
begin
  HighI := Length(Path)-1; //S4:
  if HighI < 0 then Exit;
  NewNode := TPolyNode.Create; //<-- CREATE hier wird ein Node angelegt
  NewNode.FJoinType := JoinType;
  NewNode.FEndType := EndType;

  //strip duplicate points from path and also get index to the lowest point ...
  if EndType in [etClosedLine, etClosedPolygon] then
    while (HighI > 0) and PointsEqual(Path[0], Path[HighI]) do dec(HighI);
  SetLength(NewNode.FPath, HighI +1);
  NewNode.FPath[0] := Path[0];
  J := 0; K := 0;
  for I := 1 to HighI do
    if not PointsEqual(NewNode.FPath[J], Path[I]) then
    begin
      inc(J);
      NewNode.FPath[J] := Path[I];
      if (NewNode.FPath[K].Y < Path[I].Y) or
        ((NewNode.FPath[K].Y = Path[I].Y) and
        (NewNode.FPath[K].X > Path[I].X)) then
          K := J;
    end;
  inc(J);
  if J < HighI +1 then
    SetLength(NewNode.FPath, J);
  if (EndType = etClosedPolygon) and (J < 3) then
  begin
    NewNode.free; //<-- Hier wird etwas freigegeben
    Exit;
  end;
  FPolyNodes.AddChild(NewNode); //<-- hier wird der NewNode übergeben, uns sollte dann nur in den PolyNodes referenziert sein

  if EndType <> etClosedPolygon then Exit;
  //if this path's lowest pt is lower than all the others then update FLowest
  if (FLowest.X < 0) then
  begin
    FLowest := IntPoint(FPolyNodes.ChildCount -1, K);
  end else
  begin
    ip := FPolyNodes.Childs[FLowest.X].FPath[FLowest.Y];
    if (NewNode.FPath[K].Y > ip.Y) or
      ((NewNode.FPath[K].Y = ip.Y) and
      (NewNode.FPath[K].X < ip.X)) then
        FLowest := IntPoint(FPolyNodes.ChildCount -1, K);
  end;
end;


procedure TClipperOffset.AddPaths(const Paths: TPaths;
  JoinType: TJoinType; EndType: TEndType);
var
  I: Integer;
begin
  for I := 0 to Length(Paths)-1 do
    AddPath(Paths[I], JoinType, EndType);
end;

Leider ist der Code etwas unübersichtlich und unüblich, deshalb sehe ich den Wald vor Bäumen nicht mehr.
Sieht vielleicht jemand den Fehler im Bild, oder hat schon jemand diese Library portiert ?
Ich brauche davon eigentlich nur die Offset/Inflate Routine des Polygons, es scheint aber das diese ClipperLibrary das einzige auf weiter Flur ist was das sauber lösen kann.

Wie gesagt, es funktioniert alles Super, auch unter IOS/Android, nur das ich unter iOS(android ?) MemoryLeaks bekomme.
Und Apple versteht da keinen Spass.


Siehe hier:
Zitat:
Leaked Object # Address Size Responsible Library Responsible Frame
Clipper::TClipper 1 0x15c3f2f90 144 Bytes TestNote Clipper::TClipperOffset::Clear()
Clipper::TClipper 1 0x15c3efb80 144 Bytes TestNote Clipper::TClipperOffset::Clear()
Malloc 80 Bytes 1 0x15c3e8b90 80 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Clipper::TPolyNode 1 0x15c38a800 80 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Clipper::TPolyNode 1 0x15c3f3970 80 Bytes TestNote Clipper::TClipperOffset::TClipperOffset(double, double)
Malloc 64 Bytes 1 0x15c394950 64 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Malloc 64 Bytes 2 < multiple > 128 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Clipper::TPolyNode 2 < multiple > 160 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Clipper::TPolyNode 1 0x15c381a70 80 Bytes TestNote Clipper::TClipperOffset::AddPath(System:ynamicAr ray<Clipper::TIntPoint>, Clipper::TJoinType, Clipper::TEndType)
Clipper::TPolyNode 2 < multiple > 160 Bytes TestNote Clipper::TClipperOffset::TClipperOffset(double, double)
Clipper::TClipper 2 < multiple > 288 Bytes TestNote Clipper::TClipperOffset::Clear()
Clipper::TPolyNode 1 0x15c3ec7c0 80 Bytes TestNote Clipper::TClipperOffset::TClipperOffset(double, double)
P.S. Die Smilies sind nicht von mir, sondern aus dem Instruments Tool. Ich könnte heulen

Rollo
  Mit Zitat antworten Zitat