Перейти к содержанию
Fire Monkey от А до Я
  • 0

Очередной вопрос про удаление объектов в ARC


xenon54

Вопрос

procedure TForm1.Button1Click(Sender: TObject);
var
t : TImage;
begin
  t := TImage.Create(Form1);
  Memo1.Lines.Add(IntToStr( t.RefCount ) );
  t.Parent := form1;
  t.Width := 50;
  t.Height := 50;
  Memo1.Lines.Add(IntToStr( t.RefCount ) );
  t.Bitmap.Assign(image1.Bitmap);
  Memo1.Lines.Add(IntToStr( t.RefCount ) );
  t.tag := 11;
  Memo1.Lines.Add(IntToStr( t.RefCount ) );
end;

procedure TForm1.Button2Click(Sender: TObject);
var
i : Integer;
begin
  Memo1.Lines.Add('---------------------');
  for I := 0 to Form1.ComponentCount-1 do
  begin
    if Components[i] is TImage then
      if Components[i].Tag = 11 then
      begin
        Memo1.Lines.Add(IntToStr( TImage( Components[i] ).RefCount )  + ' - ' + IntToStr( Components[i].Tag ) );
        TImage( Components[i] ).Parent := nil;
        Memo1.Lines.Add(IntToStr( TImage( Components[i] ).RefCount )  + ' - ' + IntToStr( Components[i].Tag ) );
      end;
  end;
end;

Вот результат memo после одного клика по button1 и одного клика по button2:

5
7
7
7
------------------------------
9 - 11
10 - 11

После этого делаю еще 1 клик по button2 и получаю:

7 - 11
10 - 11
  1. Кто-нибудь может объяснить почему RefCount такой большой? Ведь по идее в самом начале на объект ссылается только сама переменная "T" и плюс ссылка в списке "components" у form1.
  2. После выхода из процедуры "button1click" локальная переменная(ссылка на объект)  "T" уничтожается и ее можно не считать, я правильно понял?
  3. Почему RefCount равен не 2, а 7?
  4. Почему если в конце процедуры "button1click" написать "t := nil;" картинка пропадает с формы, ведь на нее куча ссылок если верить RefCount'у
  5. Как тогда правильно уничтожить такой объект?

Система IOS.

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Сделал еще 1 эксперимент:

procedure TForm1.Button1Click(Sender: TObject);
var
i, j : Integer;
t, t2 : TImage;
begin
  for j  := 0 to 200 do
    begin
        t := TImage.Create(Form1);
        t.Parent := form1;
        t.Width := 50;
        t.Height := 50;
        t.Bitmap.LoadFromFile( TPath.Combine(TPath.GetDocumentsPath, '1.jpg') );
        t.tag := 11;
        t := nil;

        for I := 0 to Form1.ComponentCount-1 do
        begin
          if Components[i] is TImage then
            if Components[i].Tag = 11 then
            begin
              t2 := TImage(Components[i]);
              t2.Parent := nil;
              t2.Free;
              t2 := nil;
            end;
        end;
    end;
end;

Я так понял что я правильно реализовал способ номер 2 из этой темы. При картинке размером в ~200кб приложение крашится после 2-х кликов по кнопке. А вот если Free заменить на DisposeOf, то хоть утыкайся, приложение живет. В этой теме говорится что DisposeOf "форсирует вызов деструктора, но не очищает память выделенную под объект". Что это значит? И почему описанный выше пример не освобождает память?

 

P.S.: Этот пример для Android, хотя я так понял в этом смысле поведение не отличается для IOS и Android.

Ссылка на комментарий
  • 0

ох и сколько же таких "фишечек" я уже видел ...)

мой совет: напишите лучше сразу такую вот штуку для себя:

 

TObj_helper = class helper for TObject
    procedure SetRefCount( val: Integer );
  end;
{ TObj_helper }
procedure TObj_helper.SetRefCount(val: Integer);
begin
  {$ifdef android}
  Self.FRefCount:= val;
  {$endif}
end;

я гарантирую что Вам это понадобится )

Ссылка на комментарий
  • 0

Была такая идея, но это же самый что не на есть костыль, причем в самом важнейшем аспекте программирования как управление памятью... Хотелось бы реально разобраться дело во мне (я чего-то не понимаю в работе ) или ...

Ссылка на комментарий
  • 0
Кто-нибудь может объяснить почему RefCount такой большой? Ведь по идее в самом начале на объект ссылается только сама переменная "T" и плюс ссылка в списке "components" у form1.

t := TImage.Create(Form1);

Этого вам для начала будет достаточно?

Ссылка на комментарий
  • 0

Да я кажется уже разобрался.

Видимо правильное удаление объекта в этом примере будет выглядеть так:

        for I := 0 to Form1.ComponentCount-1 do
        begin
          if Components[i] is TImage then
            if Components[i].Tag = 11 then
            begin
              t2 := TImage(Components[i]);
              t2.DisposeOf;
              t2.Parent := nil;
              t2 := nil;

            end;


        end;

Т.е. нужно выполнить следующее:

1. Удалить все ссылки на самого себя внутри объекта путем вызова деструктора через Free, но почему-то этого не достаточно, а вот DisposeOF справляется с поставленной задачей.

2. Удалить все ссылки уже непосредственно в проекте которые делал сам, это ссылка в списке Children'ов у Form1, ну и саму ссылку/переменную t2.

Ссылка на комментарий
  • 0

 

Кто-нибудь может объяснить почему RefCount такой большой? Ведь по идее в самом начале на объект ссылается только сама переменная "T" и плюс ссылка в списке "components" у form1.

t := TImage.Create(Form1);

Этого вам для начала будет достаточно?

 

 "[Weak] FOwner: TComponent;" такое объявление делает так что RefCount не увеличивается от этой ссылки.

Ссылка на комментарий
  • 0

В ХЕ8 при наличии ARC:

- метод Free эквивалентен обнулению ссылки, т.е. уменьшает счетчик на 1 и обнуляет ссылку;

- метод DisposeOf принудительно разрушает объект, но не освобождает память до обнуления всех ссылок на него, т.е. получается так называемый зомби-объект.

 

По сравнению с объектом у компонентов и контролов добавляются такие понятия как Owner и Parent, что соответственно усложняет механизм подсчета ссылок.

Изменено пользователем FIL
Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...