| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | «  : 06-05-2016 07:48 »  |  | 
 
 Привет, друзья. Почитал я гугл, чет никак. Проблема только при обработке сообщения ОС. Есть такое сообщение как WM_WINDOWPOSCHANGED, срабатывает при изменении размеров окна. Хочу собственно сохранить эти значения для удобства пользователя. Включим отображение утечек: ReportMemoryLeaksOnShutdown := true; Обработка сообщения: procedure WMWindowPosChanged(var aMessage: TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;
 procedure TfmMain.WMWindowPosChanged(var aMessage: TWMWindowPosChanged);
 begin
 inherited;
 SaveFormSize(fmMain.Width, fmMain.Height); // метод формы. на котором собственно и возникает утечка
 end;
 
 procedure TfmMain.SaveFormSize(const aWidth, aHeight: integer);
 begin
 if Assigned(AppOptions) then
 begin
 AppOptions.SetOption('GUI', 'FormWidth', inttostr(aWidth)); // Передаются в метод как const
 AppOptions.SetOption('GUI', 'FormHeight', inttostr(aHeight)); // Эти самые строки, что не освобождаются, 4шт.
 end;
 end;
 
 TOption = packed record
 Section: string;
 Name: string;
 Value: string;
 
 TOptions = class
 private
 FOptions: array of TOption;
 
 
 function TOptions.SetOption(const aSection, aName, aValue: string): boolean;
 var
 i: integer;
 Founded: boolean;
 begin
 Result:= False;
 Founded:= false;
 if (aSection = '') or (aName = '') or (aValue = '') then
 raise Exception.Create('Some of option agrument is empty!');
 for i := 0 to high(FOptions) do
 begin
 if (FOptions[i].Section = aSection) and (FOptions[i].Name = aName) then
 begin
 FOptions[i].Value:= aValue;
 Founded:= true;
 end;
 end;
 if not Founded then
 begin
 SetLength(FOptions, length(FOptions) + 1);
 FOptions[high(FOptions)].Section:= aSection;
 FOptions[high(FOptions)].Name:= aName;
 FOptions[high(FOptions)].Value:= aValue;
 end;
 FLastChange:= GetTime;
 FEmpty:= false;
 Result:= true;
 end;
 Что интересно, эти самые методы вызываются при закрытии программы, и утечек нет, а вот в обработчике есть. Не пойму в чем соль. |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| zubr 
								Гость
 | 
								|  | « Ответ #1 : 06-05-2016 08:24 »  |  | 
 
 SetLength(FOptions...  память выделяется, а где она потом удаляется? |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #2 : 06-05-2016 08:25 »  |  | 
 
 destructor TOptions.Destroy;begin
 SetLength(FOptions, 0);
 inherited Destroy;
 end;
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #3 :  06-05-2016 08:37 »   |  | 
 
 Даже так пробовал. TOption = packed recordSection: string;
 Name: string;
 Value: string;
 Procedure Clear;
 end;
 
 procedure TOption.Clear;
 begin
 Self:= Default(TOption);
 end;
 
 destructor TOptions.Destroy;
 var
 i: integer;
 begin
 for i := 0 to high(FOptions) do
 FOptions[i].Clear;
 SetLength(FOptions, 0);
 inherited Destroy;
 end;
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| x77 
								Модератор
								
								   Offline 
								Пол:    
								меняю стакан шмали на обратный билет с Марса.
								
								
								
								
								
							 | 
								|  | « Ответ #4 : 22-06-2016 00:08 »  |  | 
 
 в дельфях работа с памятью люто централизована. всеми выделениями и освобождениями памяти занимается только менеджер памяти. с 2007, если не ошибаюсь, его роль выполняет FastMM. и факт утечки константируется на основе того простого факта, что кол-во выделений памяти неравно кол-ву освобождений памяти. больше ReportMemoryLeakOnShutdown ничего не даст.  и если оно выдает ошибку на методе, это означает только, что внутри метода инициализировано больше переменных, чем освобождено. и это логично, если вы хотите внутри метода созранить какую-то инфу в каком-то объекте, так, чтобы он был доступен вне этого метода, зачем вы создаете этот объект внутри метода? создайте и инициализируйте его, например, в FormCreate, освобождайте в FormDestroy, в внутри метода просто заполняйте нужными значениями уже выделенные в памяти ячейки массива. и FastMM будет спокоен, аки испанская балерина под галаперидолом.  З.Ы. в сабж: http://www.gunsmoker.ru/2009/05/blog-post_24.html |  
						| 
								|  |  
								| « Последнее редактирование: 22-06-2016 00:09 от x77 » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #5 : 22-06-2016 08:56 »  |  | 
 
 Прочитал и все равно не понимаю в чем проблема. Да, я создал объект (между прочим было без разницы, packed record там или class) в методе, что тут такого, я его и освободил при выходе из программы деструктором, как порядочный гражданин прошелся по массиву. В других модулях также используются динамические массивы с объектами, и никаких проблем.
 В любом случае, пришлось просто отказаться вызывать его в обработчике события WM_WINDOWPOSCHANGED, а по старинке при закрытии программы. Утечка пропала.
 
 И спасибо за ссыль.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| x77 
								Модератор
								
								   Offline 
								Пол:    
								меняю стакан шмали на обратный билет с Марса.
								
								
								
								
								
							 | 
								|  | « Ответ #6 : 22-06-2016 16:47 »  |  | 
 
 насколько я понимаю, проблема в том, что метод вызывался дважды. соответственно, и объект создавался дважды, а освобождался - только один раз, в деструкторе.  насчет packed record. по дефолту записи выравниваются по границе в 8 байт. что увеличивает скорость доступа к ним. размер string в зависимости от версии дельфи может "плавать" от 256 байт до нескольких гигабайт, поэтому попытки "паковать" структуры с этим типом - они какбе сомнительны    при использовании packed record строки лучше жестко типизовать оббявляя заранее их рамер, string [10], например, только тогда это будет иметь какой-то смысл. |  
						| 
								|  |  
								| « Последнее редактирование: 22-06-2016 17:05 от x77 » |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #7 : 29-06-2016 19:30 »  |  | 
 
 метод вызывается кучу раз, когда окно меняет размер или перемещается, и как он может создастся дважды,  будет просто новый элемент массива, который потом освобождается. и оно там проверяет, нет ли в массиве объектов с таким именем параметра, если есть, меняет в нем значение, иначе новый элемент массива, все как бы) |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| x77 
								Модератор
								
								   Offline 
								Пол:    
								меняю стакан шмали на обратный билет с Марса.
								
								
								
								
								
							 | 
								|  | « Ответ #8 : 02-07-2016 22:43 »  |  | 
 
 ну судя по коду (я так понял, тут не весь код), память выделяется многократно (по кол-ву вызовов метода), а освобождается только разово. утилиты контроля памяти не делают ничего сверхЪестественного, они просто переопределяют системные методы резервирования и освобождения памяти. вставляя туда свои собственные счетчики выделений и освобождений. дельфийский менеджер памяти - это не черный ящик, вы запросто можете написать свой и назначить его вместо. и когда память выделялась больше раз, чем освобождалась - они рапортуют о memory leak, вот и все.  попробуйте задавать массив при инициализации приложения, SetLength - это тоже выделение памяти.  не видя всего кода - это гадание на кофейной гуще, поэтому извините, конечно, может я просто что-то не догоняю   |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #9 : 19-07-2016 06:25 »  |  | 
 
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| x77 
								Модератор
								
								   Offline 
								Пол:    
								меняю стакан шмали на обратный билет с Марса.
								
								
								
								
								
							 | 
								|  | « Ответ #10 : 01-08-2016 21:05 »  |  | 
 
 сорри, я тут набегами, и нотификация почему-то была отключена. если ты не против, я поковыряю код, не обещаю правда, что быстро ) |  
						| 
								|  |  
								|  |  Записан | 
 
 |  |  | 
	| 
			| 
					
						| v2 
								Помогающий    Offline | 
								|  | « Ответ #11 : 16-09-2016 16:07 »  |  | 
 
   Application.Run;end.
   и вроде энд, но тут прилетает  хеппи WM_WINDOWPOSCHANGED )) procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction);begin
 Tag := -1;                                    // можно так скостылить
 FreeApp(Action);
 end;
 //+
 procedure TfmMain.WMWindowPosChanged(var aMessage: TWMWindowPosChanged);
 begin
 if Tag=0 then begin                            // ...
 SaveFormSize(fmMain.Width, fmMain.Height);
 inherited;
 end;
 end;
 я не поклонник FreeAndNil, но если б он там был ... )) procedure TfmMain.FreeApp(var Action: TCloseAction);...
 if Assigned(AppOptions) then
 begin
 AppOptions.SetOption('GUI', 'GroupList', IntToStr(tvMain.Width));
 AppOptions.SetOption('GUI', 'FormLeft', inttostr(fmMain.Left));
 AppOptions.SetOption('GUI', 'FormTop', inttostr(fmMain.Top));
 SaveFormSize(fmMain.Width, fmMain.Height);
 if not AppOptions.SaveUserOptions() then
 raise Exception.Create('Cant''t save user options!');                                                                  // после нас хоть потоп - а, ну да, на то оно и 'raise'  )))
 AppOptions.Free;                                           // может FreeAndNil ?
 end;
 ...
 
 procedure TfmMain.SaveFormSize(const aWidth, aHeight: integer);
 begin
 if Assigned(AppOptions) then                                     // да, FreeAndNil !!!
 begin
 AppOptions.SetOption('GUI', 'FormWidth', inttostr(aWidth));
 AppOptions.SetOption('GUI', 'FormHeight', inttostr(aHeight));
 end;
 end;
 и еще (что заметилось): function TOptions.SetOption(const aSection, aName, aValue: string): boolean;...
 for i := 0 to high(FOptions) do
 begin
 if (FOptions[i].Section = aSection) and (FOptions[i].Name = aName) then
 begin
 FOptions[i].Value:= aValue;
 Founded:= true;
 Break;                                  // не помешает
 end;
 end;
 ...
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	| 
			| 
					
						| SCRIBE 
								Гость
 | 
								|  | « Ответ #12 : 17-09-2016 17:41 »  |  | 
 
 Насчет Assigned, да, обманчив он, чисто проверка на Nil, работать должен с FreeAndNil.
 Вот значит как, объект с настройками освободился, а виндовс пытается в него запихнуть значения...
 Спасибо огромное человек, флаг на начало закрытия формы уже можно сообразить.
 |  
						| 
								|  |  
								|  |  Записан | 
 |  |  | 
	|  |