Форум: "Прочее";
Текущий архив: 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 структур данных, но их можно написать самому. Например, очередь - первый кандидат для этого.
← →
Eraser © (2016-03-27 14:00) [41]синхронизация - это действительно костыль, используется крайне редко. но местами без него нельзя.
и уж точно нельзя использовать для отображения прогресса, либо каких-то относительно простых данных в GUI. это делается через простой таймер в основном потоке и проверки по нему нужных свойств потока, предварительно защитив их крит. секцией, конечно.
← →
DVM © (2016-03-27 15:51) [42]
> Eraser © (27.03.16 14:00) [41]
> синхронизация - это действительно костыль, используется
> крайне редко.
Наверное это ты о Synchronize конкретно. В общем случае у меня редко какой поток обходится без синхронизированного доступа к каким либо ресурсам.
← →
Eraser © (2016-03-27 16:18) [43]
> Наверное это ты о Synchronize конкретно
да, о нем конечно.
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2017.03.12;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.002 c