Конференция "KOL" » Утечка GDI-ресурсов [Delphi, Windows]
 
Ошибка соединения. delphimaster.php on line 504
Ошибка соединения. delphimaster.php on line 737
  • G-Host © (10.02.12 02:03) [20]
    2 everyone
    If you wish, you can check it by yourself downloading EXE & project here:
    http://dl.dropbox.com/u/5169980/test_kol.zip
  • RusSun © (11.02.12 20:37) [21]
    @thaddy: Reading without action for me like no reaction)
  • Thaddy © (13.02.12 16:54) [22]
    Action taken right now. I'll have a look...
    Was easier by email...
  • Thaddy © (13.02.12 17:23) [23]
    After one minute:

    procedure TForm1.Button1Click(Sender: PObj);
    var
     i : Integer;
    begin
    //  //start monkey (strictly speaking amoebe code)
    //  for I := 1 to 4000 do
    //  begin
    //    lv := NewListView(Form, lvsList, [], nil, nil, nil);
    //    lv.Show;
    //    lv.Free;
    //  end;
     for I := 1 to 4000 do
     begin
       // start homo erectus code (strictly speaking: monkey code <smile>)
       lv := NewListView(Form, lvsList, [], nil, nil, nil);
       try  //protect your object!
         lv.Show;
       finally
         lv.Free;
       end;
     end;

    end;


    No leaks....

    Slightly improved.....

     form.BeginUpdate; // Leave the rest of your apps alone, get a rest.
     try  // but make sure you get the screen back when we are finished
       for I := 1 to 4000 do
       begin
       // start homo sapiens code (strictly speaking: homo erectus code <smile>)
         lv := NewListView(Form, lvsList, [], nil, nil, nil);
         try //protect your object
           lv.Show;
         finally
           lv.Free;
         end;
       finally
         Form.EndUpdate;
       end;
    end;


    No leaks at all....

    And finally:

    procedure TForm1.Button2Click(Sender: PObj);
    begin
    // double free may look like a leak but isn't
     if Assigned(lv) then lv.Free;
    end;



    Case closed.
  • thaddy © (13.02.12 17:29) [24]
    BTW the trick is of course:

    SHOWMODAL!
  • thaddy © (13.02.12 17:41) [25]
    The lesson is: your program doesn't have full control over OS resources when your application has no time to respond to messages. Although Autofree does a good job, it still needs to be notified. AND you are creating the listview in a procedure again and again. in that case NO framework can guarantee that the original object is already freed. By using a try finally block you can prevent this.
    Second mistake: you use show, where you really want to use either showmodal or use the virtual listview option (Vladimir has an excellent example on kolmck,net)
    Third mistake: too many screen updates... Lock the form, with begin update ensures that no paint messages are send until you are finished with your work (be sure to unlock it!)
    Fourth mistake:
    The way you have written the code can cause the conflict that there is no listview at all, so you have to check if it is not already destroyed.

    If you test your code with my small improvements, you will find that it does not leak at all. But good programming is completely different. I can point you to at least a dozen other basic mistakes in the rest of the your program.
  • thaddy © (13.02.12 17:54) [26]
    Easy to make mistakes:

    form.BeginUpdate; // Leave the rest of your apps alone, get a rest.
    try  // but make sure you get the screen back when we are finished
      for I := 1 to 4000 do
      begin
      // start homo sapiens code (strictly speaking: homo erectus code <smile>)
        lv := NewListView(Form, lvsList, [], nil, nil, nil);
        try //protect your object
          lv.Show;
        finally
          lv.Free;
        end;
      end;
    finally
       Form.EndUpdate;
    end;
    end;

  • Thaddy © (13.02.12 20:34) [27]
    It doesn't leak, but it does not show either <smile>
    Programming in human memory isn't without flaws...
    But then again: the code is nonsense.
    Why would you do that?
    In the VCL application you solved things more normal. But with a totally different algorithm. Your KOL code has to many mistakes anyway.

    If you really want to create a new listview object every 4000 times --- do the screen lock in the loop too..... It still doesn't leak and this time everything is tested with memproof (I can prove it!)
  • G-Host © (14.02.12 13:08) [28]
    2 thaddy:
    Please send me a compiled EXE and project source of example, which create and destroy 4000 ListViews
  • G-Host © (22.02.12 01:00) [29]
    В общем, ответа от thaddy нет, а проблема остается - создать (и уничтожить) 4000 ListView в программе на KOL не представляется возможным.
    Причем не важно, сразу создавать или размазывать код по времени.
  • Dufa © (22.02.12 19:06) [30]
    Страдаете откровенной ерундой.

    вот код, утечек нет.

    procedure TForm1.Button1Click(Sender: PObj);
    var
     i : Integer;
    begin
     for I := 1 to 4000 do begin
       lv := NewListView(Form, lvsList, [], nil, nil, nil);
       lv.SetPosition(0, 0).SetSize(20, 20);
       Form.Invalidate;
       lv.Free;
     end;
    end;

    а так же читаем комменты в коле

       procedure Show;
       {* |<#appbutton>
          |<#form>
          Makes control visible and activates it. }

    где тут написано что можно юзать метод с листвью?

  • Vladimir Kladov © (22.02.12 23:12) [31]
    Попробуйте UNICODE_CTRLS. В новых Delphi начиная с 2009, как я понимаю, иначе и не получается, там этот символ просто должен быть. (Хорошо бы еще понять, как сделать, чтобы утечки не было без него - для старых Delphi. Возможно, надо отлавливать какое-нибудь событие с W на конце имени, хотя контрол и не уникодовский. Первый раз подобное было замечено с treeview).

    2Dufa: Однако, можно. Не помню как раньше (и было ли иначе), но сейчас это то же самое что Visible := true;
  • Vladimir Kladov © (23.02.12 16:46) [32]
    Все, разобрался. Действительно, UNICODE не при чем. Действительно, имеется утечка - именно для ListView. Надо было отнести код, удаляющий привязку контрола к окну, в WM_NCDESTROY. Есть некоторые сомнения, что абсолютно все будет работать корректно:
    - как минимум, пришлось вызвать обработчик WM_NCDESTROY по умолчанию
    - так же, в коде есть комментарий по поводу исправления для корректного уничтожения progress bar'а (версия 2.41-2.42). Я проверил - вроде бы все нормально после переноса, но может, я что-то не учел.
    - дополнительно, есть вероятность, что требуется проверка того, что сообщение WM_DESTROY / WM_NCDESTROY пришло от своего собственного окна. Заключение в кавычки {IFnDEF SMALLER_CODE}, видимо, достаточно - в общем случае проверка останется.
    - изменения могут привести к тому, что несколько больше обработчиков событий и оконных сообщений может срабатывать в момент разрушения контрола или формы. Но в принципе, особых проблем не наблюдается - на тестах.

    Сейчас я приготовлю обновление. Если есть пожелания о внесении в версию каких-либо изменений, пишите сейчас.
  • rdnks (23.02.12 17:43) [33]
    хотелось бы для мост копабилити в TKOLStrList между анси и юникодом наблюдать property values


    // kol.pas
    //[...]

    interface

    //[...]

    type
     PWStrList = ^TWstrList;
     {* }

    //[...]

       procedure OptimizeForRead;
    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Начало блока
     protected
       procedure SetValue(const AName, Value: KOLWideString);
       function GetValue(const AName: KOLWideString): KOLWideString;
     public
       function IndexOfName(AName: KOLWideString): Integer;
       property Values[const AName: KOLWideString]: KOLWideString read GetValue write SetValue;
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Конец блока
     end;

    //[...]

    implementation

    //[...]

    procedure TWStrList.OptimizeForRead;
    begin
       {$IFDEF TLIST_FAST}
       if  fList <> nil then
           fList.OptimizeForRead;
       {$ENDIF}
    end;

    // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Начало блока
    function TWStrList.IndexOfName(AName: KOLWideString): Integer;
    var i: Integer;
       L: Integer;
       fCount: integer;
    begin
       Result:=-1;
       L := Length( AName );
       if L > 0 then
       begin
         AName := WLowerCase( AName ) + fNameDelim;
         Inc( L );
         fCount := GetCount - 1;
         for i := 0 to fCount do
         begin
           if _WStrLComp( PWideChar( WLowerCase( ItemPtrs[ i ] ) ), PWideChar( AName ), L ) = 0 then
           begin
             Result:=i; exit; {>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}
           end;
         end;
       end;
    end;

    procedure TWStrList.SetValue(const AName, Value: KOLWideString);
    var
     I: Integer;
    begin
     I := IndexOfName(AName);
     if i=-1
     then Add( AName + fNameDelim + Value )
     else Items[i] := AName + fNameDelim + Value;
    end;

    function TWStrList.GetValue(const AName: KOLWideString): KOLWideString;
    var
     i: Integer;
    begin
     I := IndexOfName(AName);
     if I >= 0
     then Result := Copy(Items[i], Length(AName) + 2, Length(Items[i])-Length(AName)-1)
     else Result := '';
    end;
    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Конец блока

  • Vladimir Kladov © (23.02.12 19:32) [34]
    так, еще?
 
Конференция "KOL" » Утечка GDI-ресурсов [Delphi, Windows]
Есть новые Нет новых   [118488   +58][b:0][p:0.004]