Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2017.03.12;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.002 c
8-1208967764
Darkmoon
2008-04-23 20:22
2017.03.12
Альфа канал


3-1312799506
Quart
2011-08-08 14:31
2017.03.12
пустой GUID


15-1458755602
Dimka Maslov
2016-03-23 20:53
2017.03.12
Как жить дальше?


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


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





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский