Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2017.03.12;
Скачать: CL | DM;

Вниз

Как жить дальше?   Найти похожие ветки 

 
Dimka Maslov ©   (2016-03-23 20:53) [0]

В стародавние времена для поиска утечек памяти пользовался я FastMMом. Всё было хорошо. Но теперь, в нынешнюю годину суровых испытаний, с появлением у меня Delphi XE8 я заметил, что FastMM больше не нужен, а достаточно лишь прямо в программе указать ReportMemoryLeaksOnShutdown := True. Вроде всё хорошо, но что-то не хорошо. А именно, раньше я мог сконфигурировать всё так, чтобы при выходе из программы ещё и файлик содавался, в котором указывалось, где утёкший блок был выделен. Теперь же можно только имя класса узнать, который утёк. Или всё таки можно как-нибудь изловчиться?


 
Rouse_ ©   (2016-03-23 21:02) [1]

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


 
Dimka Maslov ©   (2016-03-23 22:03) [2]

Т.е. всё сделать как по старому и всё заработает? А если у меня 64-бита приложение? (А оно у меня реально 64 бита).


 
DVM ©   (2016-03-23 22:54) [3]


>
> Dimka Maslov ©   (23.03.16 20:53) 

В Delphi насколько я знаю встроен урезанный FastMM4. Никто не запрещает подключить и обычный.


 
Rouse_ ©   (2016-03-23 23:47) [4]

за 64 бита не подскажу - в 32 битах работает норм.


 
Дмитрий Белькевич ©   (2016-03-24 00:35) [5]

64 норм тоже. и да, в делфе вроде урезанный. я подключаю.


 
Dimka Maslov ©   (2016-03-24 08:38) [6]

Понятно, спасибо.

Только вот ещё такой вопрос. Почему когда я внутри тела потока (в перекрытом методе Execute) делаю Free - оно ругается на невысвобожденную память из-под класса потока (хотя деструктор срабатывает и все поля объекты и строки высвобождены), а вот когда я указываю FreeOnTerminate := True и Terminate, то не ругается? Это очередной баг?


 
Владислав ©   (2016-03-24 10:31) [7]

> Dimka Maslov ©   (24.03.16 08:38) [6]

Почему когда я внутри тела потока (в перекрытом методе Execute) делаю Free

Кому Free, экземпляру класса исполняемого потока???


 
Dimka Maslov ©   (2016-03-24 10:45) [8]


> Кому Free, экземпляру класса исполняемого потока???


Кому же ещё?


 
Юрий Зотов ©   (2016-03-24 11:03) [9]

То есть, создавался объект в одном потоке, а уничтожается в другом?


 
Dimka Maslov ©   (2016-03-24 11:04) [10]


> То есть, создавался объект в одном потоке, а уничтожается
> в другом?


Что в этом плохого?


 
Владислав ©   (2016-03-24 12:16) [11]

> Dimka Maslov ©   (24.03.16 10:45) [8]

Кому же ещё?

Это потоковая функция:

function ThreadProc(Thread: TThread): Integer;
...
begin
...
 try
   if not Thread.Terminated then
   try
     Thread.Execute; <========= Вот тут Вы грохаете экземпляр
   except
     Thread.FFatalException := AcquireExceptionObject; <======= Далее по тексту идут обращения к грохнутому экземпляру
   end;
 finally
   FreeThread := Thread.FFreeOnTerminate;
   Result := Thread.FReturnValue;
   Thread.DoTerminate;
   Thread.FFinished := True;
   SignalSyncEvent;
   if FreeThread then Thread.Free; <=========== А тут экземпляр может еще раз грохнуться
...
end;


 
Dimka Maslov ©   (2016-03-24 12:39) [12]


> Вот тут Вы грохаете экземпляр


В том и вопрос, что он вообще не грохается.


 
Владислав ©   (2016-03-24 13:45) [13]

Грохается:

"... (хотя деструктор срабатывает и все поля объекты и строки высвобождены) ..."

И так делать нельзя (освобождать экземпляр класса TThread в методе Execute)!

"... а вот когда я указываю FreeOnTerminate := True и Terminate... "

Вот так, как выше написали, так и поступайте, раз Вам экземпляр после запуска потока не нужен.


 
Dimka Maslov ©   (2016-03-24 14:10) [14]

В общем, CreateThread - Наше всё!


 
NoUser ©   (2016-03-24 14:27) [15]

> Это очередной баг?
Да , TThread это зло - BeginThread наше всё  ))
Free -> WaitForSingleObject(FHandle, INFINITE); // !


 
Владислав ©   (2016-03-24 14:49) [16]

> Dimka Maslov ©   (24.03.16 14:10) [14]

Да почему же. Почитать немного на эту тему.

Ну и только не CreateThread, а BeginThread.


 
Dimka Maslov ©   (2016-03-24 20:15) [17]

Таки Create https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx


 
Nouser ©   (2016-03-24 21:00) [18]

Даж сишники стремаются: _beginthread/ex
А так можно такую штучку замутить
TWork.Add(BeginThread(nil, 0, @TWork.Run, TWork.Create, 0, PCardinal(0)^)); // ))


 
Владислав ©   (2016-03-24 22:23) [19]

>Dimka Maslov ©   (24.03.16 20:15) [17]

А может все же почитать? Или самому по граблям интереснее? :)


 
Dimka Maslov ©   (2016-03-24 22:59) [20]

Так я и почитал. Всё ясно и понятно написано. В отличие от сайа некоей конторы.


 
DVM ©   (2016-03-24 23:17) [21]


> Dimka Maslov ©   (24.03.16 20:15) [17]

1) Не кроссплатформенно
2) Не выставляет флаг IsMultithreaded автоматом.


 
Kerk ©   (2016-03-24 23:57) [22]

А чем можно смотреть использование памяти в рантайм? В смысле - сделать снимок и посмотреть кто, сколько и для чего памяти выделил. Бывает такое бесплатное?


 
Германн ©   (2016-03-25 01:55) [23]


> Dimka Maslov ©   (24.03.16 12:39) [12]
>
>
> > Вот тут Вы грохаете экземпляр
>
>
> В том и вопрос, что он вообще не грохается.

на каких основаниях сделан такой вывод.


 
Eraser ©   (2016-03-25 05:38) [24]


> Dimka Maslov ©   (24.03.16 08:38) [6]

TThread - один из самых удобных классов в Делфи. Разве что потоковые нововведения в самых новых версиях делфи могут соперничать (parallel lib).
Прежде чем использовать TThread, нужно проникнуться его идеологией, хотя бы поверхностно, а не кидаться удалять объект изнутри самого себя.
Одна из сильнейших сторон TThread - событие OnTerminate, выполняющиеся всегда в контексте главного потока.

Вообще современный TThread чего только не умеет.


procedure TForm1.Button1Click(Sender: TObject);
var
 I: Integer;
begin
 I := 1;
 TThread.CreateAnonymousThread(
   procedure
   begin
     Inc(I);
     TThread.Queue(nil,
       procedure
       begin
         ShowMessage(I.ToString);
       end
     );
   end
 ).Start;
end;


 
Dimka Maslov ©   (2016-03-25 09:38) [25]


> 1) Не кроссплатформенно


И пёс с им.


> на каких основаниях сделан такой вывод.


На основании анализа утечек памяти.


>  событие OnTerminate


Легко заменяется на SendMessage(Application.MainFormHandle, .....), которое тоже выполнится в контексте главного потока.


 
DVM ©   (2016-03-25 11:41) [26]


> Dimka Maslov ©   (25.03.16 09:38) [25]


> Легко заменяется на SendMessage(Application.MainFormHandle,
>  .....), которое тоже выполнится в контексте главного потока.

При условии наличия окон в программе и цикла выборки сообщений. OnTerminate не требует окон.


 
NoUser ©   (2016-03-25 14:48) [27]

> OnTerminate не требует окон.
А чего тогда требует?


 
DVM ©   (2016-03-25 17:00) [28]


> NoUser ©   (25.03.16 14:48) [27]


> А чего тогда требует?

OnTerminate через  Synchronize вызывается. Теперешний Synchronize уже не использует сообщений как раньше. Подробности см. реализацию Synchronize


 
NoUser ©   (2016-03-25 17:50) [29]

Вот мне и интересно, как сделать основной поток (без окон), чтобы этот OnTerminate там отработал?


 
DVM ©   (2016-03-25 18:17) [30]


> Вот мне и интересно, как сделать основной поток (без окон),
>  чтобы этот OnTerminate там отработал?


program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
 System.SysUtils, System.Classes;

type

 TMyThread = class(TThread)
 protected
   procedure Execute; override;
 end;

 TMyClass = class
 private
   FSecondThread: TMyThread;
   procedure ThreadTreminated(Sender: TObject);
 public
   constructor Create;
   destructor Destroy; override;
   procedure Run;
 end;

var
 MyClass: TMyClass;

{ TMyClass }

constructor TMyClass.Create;
begin
 inherited Create;
 FSecondThread := TMyThread.Create;
 FSecondThread.FreeOnTerminate := True;
 FSecondThread.OnTerminate := ThreadTreminated;
end;

destructor TMyClass.Destroy;
begin
 FSecondThread.Free;
 inherited;
end;

procedure TMyClass.Run;
var
 i: integer;
begin
 for I := 0 to 9 do
   begin
     Writeln(I);
     CheckSynchronize;
     Sleep(1000);
   end;
end;

procedure TMyClass.ThreadTreminated(Sender: TObject);
begin
 Writeln("Second thread terminated");
end;

{ TMyThread }

procedure TMyThread.Execute;
begin
 Writeln("Second thread start");
 Sleep(2000);
 Writeln("Second thread end");
end;

begin
 try
   MyClass := TMyClass.Create;
   try
     MyClass.Run;
   finally
     MyClass.Free;
   end;

 except
   on E: Exception do
     Writeln(E.ClassName, ": ", E.Message);
 end;
 Readln;
end.


 
DVM ©   (2016-03-25 18:20) [31]

Небольшое уточнение, надо убрать FSecondThread.FreeOnTerminate := True;


 
NoUser ©   (2016-03-25 19:07) [32]

Спасибо, но как я и думал, чуда не произошло - CheckSynchronize.
ЗЫ.
А какая версия Dx ?


 
DVM ©   (2016-03-25 21:46) [33]


> NoUser ©   (25.03.16 19:07) [32]


> чуда не произошло - CheckSynchronize.

Разумеется, чуда никакого нет и не может быть. Никто, кроме самого потока не может выполнить код в его контексте. Собственно внутри CheckSynchronize и происходит выборка из очереди действия для выполнения потоком и собственно выполнение.


> А какая версия Dx ?
>
>

У меня D8. Но CheckSynchronize  существует очень давно, в 2009 уже было вроде, а может и раньше.


 
Германн ©   (2016-03-25 23:05) [34]

Раньше. В Д2007 точно был.


 
Dimka Maslov ©   (2016-03-27 09:45) [35]


> Теперешний Synchronize уже не использует сообщений


Если покопаться поглубже, то теперешний Synchronize использует WakeMainThread (глобальное событие), которое установлено в Application.WakeMainThread, внутри которого делается PostMessage(Handle, WM_NULL, 0, 0) самому объекту Application, который вызывает CheckSynchronize.

Таким образом, делаем вывод, что нет никакого Synchronize, который уже не использует сообщений...


 
DVM ©   (2016-03-27 10:27) [36]


> Dimka Maslov ©   (27.03.16 09:45) [35]


> внутри которого делается PostMessage(Handle, WM_NULL, 0,
>  0) самому объекту Application, который вызывает CheckSynchronize.
>  

Ты не путай людей. Это внутренняя кухня исключительно объекта Application, а не Syncronize. То, что Application так реагирует на WakeMainThread это исключительно его дело. Syncronize может работать и без всяких Application, окон и циклов выборки сообщений, как я показал выше. В объекте Application это сделано исключительно в целях повышения отзывчивости его на Syncronize, с таким же успехом он мог раз в секунду проверять CheckSynchronize.


 
Dimka Maslov ©   (2016-03-27 10:44) [37]


> DVM ©   (27.03.16 10:27) [36]


Но ведь если нет цикла обработки сообщений и я сам не позаботился проверять CheckSynchronize, то синхронизация с основным потоком вообще не будет работать! Более того, в описании System.Classes.TThread.Synchronize ничего явно не сказано про CheckSynchronize. Надо из-под корки догадаться прочитать в See Also.

И ещё. Когда-то давно, лет пять назад, я сделал синхронизацию вычислительного потока с основным через вот этот самый Synchronize. Работало настолько медленно, что считать стало просто невозможно. Пришлось повыкидывать всё это и поставить критические секции.


 
DVM ©   (2016-03-27 10:51) [38]


> Но ведь если нет цикла обработки сообщений и я сам не позаботился
> проверять CheckSynchronize, то синхронизация с основным
> потоком вообще не будет работать!

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


> Когда-то давно, лет пять назад, я сделал синхронизацию вычислительного
> потока с основным через вот этот самый Synchronize. Работало
> настолько медленно, что считать стало просто невозможно.
>  

Ну это все равно придумывалось ради синхронизации с GUI потоком, там вряд ли нужна какая то особая скорость. Тот кто хочет синхронизировать свои потоки друг с другом сам придумает более эффективные реализации в каждом конкретном случае. Вообще имхо - синхронизация  - зло, можешь не синхронизировать - не синхронизируй.


 
Dimka Maslov ©   (2016-03-27 11:09) [39]


> синхронизация  - зло, можешь не синхронизировать - не синхронизируй


Золотые слова. Вот только не синхронизироваться в Delphi нельзя.


 
DVM ©   (2016-03-27 11:26) [40]


> Dimka Maslov ©   (27.03.16 11:09) [39]


> Вот только не синхронизироваться в Delphi нельзя.

С GUI да, но в остальных случаях можно придумать рабочие варианты. Хоть в делфи нет LockFree структур данных, но их можно написать самому. Например, очередь - первый кандидат для этого.



Страницы: 1 2 вся ветка

Текущий архив: 2017.03.12;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.005 c
2-1436124496
Арт
2015-07-05 22:28
2017.03.12
Переход по записям в ADO


8-1208967764
Darkmoon
2008-04-23 20:22
2017.03.12
Альфа канал


2-1435584756
Артемка
2015-06-29 16:32
2017.03.12
Составной SQL-запрос


1-1349251842
de_guta
2012-10-03 12:10
2017.03.12
Проблема с записью в массив


15-1459032676
Kilkennycat
2016-03-27 01:51
2017.03.12
Qt.