Утечка памяти в TPacker.SplitNode - PullRequest
0 голосов
/ 29 января 2019

Я нашел в сети простой бинарный упаковщик, который я изменил в соответствии со своими потребностями.Это работает хорошо, но у меня течет память.

TSprite

type
  TSprite=class
  public
    X:Integer;
    Y:Integer;
    Width:Integer;
    Height:Integer;
    Used:Boolean;
    Down:TSprite;
    Right:TSprite;
    constructor Create(X, Y,Width, Height:Integer);
end;

TPacker

type
  TPacker=class
  public
  Root:TSprite;
  constructor Create(W,H:Integer; Image : TImage);
  destructor Destroy; override;
  function Fit(var Blocks:array of TBlock):Boolean;
  function FindNode(root:TSprite; W, H:Integer):TSprite;
  function SplitNode(Node:Tsprite; W, H:Integer):TSprite;
end;

Я использую это так

var Packer:TPacker;

  Packer:=TPacker.Create(Width  , Height, Image);

  Packer.Fit(Blocks);

  Boundary(Packer.Root, Image);

  for I := Low(Blocks) to High(Blocks) do
    begin
      if Blocks[I].Fit <> nil then
        Draw(Blocks[I].Fit.X,Blocks[I].Fit.Y,Blocks[I].Width,Blocks[I].Height, Image);
    end;



  LeftRacks:=Report(blocks, packer.Root.Width, packer.Root.Height).Racks;
  FillPercent:=Report(blocks, packer.Root.Width, packer.Root.Height).FillPercent;

  Packer.Free;

Конструктор для TPacker

constructor TPacker.Create(W: Integer; H: Integer; Image : TImage);
var temp : integer;
begin
  // 100x100 is our smalles unit . So to create a nice Packview we always
  // change W,H to neerest value which is dividable by 100.
  temp:=0;
  temp:=W mod 100;
  W:=W-temp;

  temp:=0;
  temp:= H mod 100;
  H:=H-temp;

  Image.Width:=W+1;
  Image.Height:=H+1;

  Self.Root := TSprite.Create(0,0,W,H);
  Self.Root.Used:=false;
  Self.Root.Down:=nil;
  Self.Root.Right:=nil;
end;

Вот первая утечка памяти, которую я исправил в деструкторе

destructor TPacker.Destroy;
begin
  FreeAndNil(Root);

  inherited;
end;

Утечка тока происходит в SplitNode, потому чтоон создает новые узлы, в которых я теряю трек, и я не знаю, как правильно их освободить.

function TPacker.SplitNode(Node: TSprite; W: Integer; H: Integer):TSprite;
begin
  Node.Used := true;
    Node.Down := TSprite.Create(Node.X , Node.Y + H , Node.Width , Node.Height - H);
    Node.Right := TSprite.Create(Node.X + W , Node.Y , Node.Width - W , H);
  Result := Node;
end;

SplitNode используется в этой Fit функции

function TPacker.Fit(var Blocks: array of TBlock):Boolean;
var
  I:Integer;
  Node:TSprite;
  temp:integer;
begin
   for I := Low(Blocks) to High(Blocks) do
    begin
      Node:=Self.FindNode(Self.Root, Blocks[I].Width, Blocks[I].Height);
      // we rotate it and try again just in case...
      if Assigned(Node) = false then
        begin
          temp:=Blocks[I].Width;
          Blocks[I].Width:=Blocks[I].Height;
          Blocks[I].Height:=temp;

          Node:=Self.FindNode(Self.Root, Blocks[I].Width, Blocks[I].Height);
        end;

      if Assigned(Node) then
        begin
          Blocks[I].Fit := Self.SplitNode(node, Blocks[I].Width, Blocks[I].Height);
        end;
    end;
end;

1 Ответ

0 голосов
/ 29 января 2019

Вы явно создаете и уничтожаете TSprite, используемый как Root в классе TPacker.Но SplitNode создает намного больше TSprite объектов неявно в древовидной структуре.Не существует автоматов, которые бы убирали эти дополнительные объекты.На эти TSprite ссылаются, хотя (Down и Right), поэтому каждый TSprite имеет ссылки на дополнительные TSprite s, на которые он был разбит, и может их очистить.Если каждый из них выполнит эту очистку, все дерево будет рекурсивно уничтожено.

Поэтому решение состоит в том, чтобы написать деструктор для TSprite:

destructor TSprite.Destroy;
begin
  Down.Free;
  Right.Free;
  inherited;
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...