Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Pchar Замена подстроки в строке


Автор: lollollollol 3.4.2013, 07:12
Ещё раз всех приветствую.

На этапе тестирования софта заметил утечку памяти. 
И судя по всему проблема в том, что у меня используются длинные строки string(больше 255 символов).

Решил переписать всё, оставив только Pchar, но столкнулся с проблемой, обычные функции, котрыми я выполняю поиск подстроки в строке не раотают с типом Pchar

В гугле я тоже не нашел решения, да и сам не смог осилить, прошу помочь, необходима функция замены подстроки в строке Pchar.

Cпасибо

Добавлено @ 07:23
Или может быть проще избавиться от утечки памяти при длинных строках string? Хотя думаю правильнее отказаться от string

Автор: Poseidon 3.4.2013, 08:16
string без указания количества символов - это либо UnicodeString, либо AnsiString (в зависимости от версии среды). Никаких утечек памяти при использовании этого типа быть не может.

Для замены подстроки в строке обычно используют StringReplace. Да, там используются string. Если тебе уж так очень надо писать без string, то наваяй свою функцию, это же не запрещено.

Цитата(lollollollol @  3.4.2013,  07:12 Найти цитируемый пост)
Или может быть проще избавиться от утечки памяти при длинных строках string? Хотя думаю правильнее отказаться от string
Я постоянно пользуюсь string и утечек по этому поводу не наблюдаю. Не знаю откуда у тебя сложилось такое ошибочное мнение, что из-за string происходят утечки.

Автор: lollollollol 3.4.2013, 09:06
Код

    if (pos(' /style.css',str_buff)<>0) then begin
      buff:='HTTP/1.1 200 OK'+#13#10+'Server: Apache/2'+#13#10+'X-Powered-By: PHP/5.2.17'+#13#10+'Vary: Accept-Encoding,User-Agent'+#13#10+'Content-Length: 3000'+#13#10+'Keep-Alive: timeout=1, max=100'+#13#10+'Connection: Keep-Alive'+#13#10+'Content-Type: text/css'+#13#10+#13#10;
      buff:=buff+'body  {margin: 0 auto; padding: 0;  width: 100%; height: 100%; background: #f5f5f5 repeat;} body, td {font:11px Verdana,Arial,Helvetica, sans-serif; color:#555;} img {border: none;} a:link, a:visited  {color:#2C68A6;}';
//тут идёт дальше формирование css кода, примерно 1000 символов в сумме
      send(recvsock,buff[1],length(buff),0);
    end;


В результате каждый раз, когда я запрашиваю страничку, диспетчер показывает увеличение памяти. И только увеличение

Автор: Illusion Dolphin 3.4.2013, 09:27
fastmm подключать пробовали?

Автор: lollollollol 3.4.2013, 09:32
нет, дже не слшал про это

Автор: Illusion Dolphin 3.4.2013, 09:36
Подключите, увидите, есть ли утечки, а также поможет найти места, где они появляются. Я бы без fastmm не грешил на string, ни разу не видел чтобы он куда-то утекал.
http://sourceforge.net/projects/fastmm/ 

Автор: lollollollol 3.4.2013, 09:38
Скачал, подключил, на удивление софт стал в нескоько раз быстрее выполнять основной рабочий код.
Но стабильно кидает Access Violation в модуле FastMM4 на строке
Код

  {Unlock the block type}
  mov TSmallBlockType[ebx].BlockTypeLocked, al

или
Код

  {Get the new first free block}
  and ecx, [eax - 4]


Добавлено через 8 минут и 21 секунду
А как с его помощью определить место утечки?
Прога не должна больше 2-х метров весить, через 5 минут работы уже 50 мегов

Автор: Beltar 3.4.2013, 09:52
Показания диспетчера не значат абсолютно ничего. Утечек и AV с PChar словишь в миллион раз больше, чем со String для которого все выделение и освобождение памяти производится автоматически. А еще если у тебя часто приходится получать длину строки.  smile Не вижу никаких оснований использовать эту мерзость, кроме как для преобразования типов при вызове API-функций.
http://www.gunsmoker.ru/2010/02/redux.html

Добавлено через 4 минуты и 12 секунд
Цитата

Прога не должна больше 2-х метров весить, через 5 минут работы уже 50 мегов


Так для релиза дебажные настройки выруби, у меня вот сейчас выходной экзешник из XE3 с подключенным для full debug FastMM4 весит 21.5 Мб. smile Релизный вариант меньше 3 (Юникодовые версии компактностью экзешек не отличаются).

И какая версия FastMM? Может надо последнюю качнуть?

Автор: lollollollol 3.4.2013, 09:59
Скачал отсюда
http://sourceforge.net/projects/fastmm/

сам ехе 88кб весит, а вот в памяти должен 2 мегобайта занимать. Но каждый раз когда я записыаю длинные строки (цыклом) увеличивается память.

И обратно не уменьшается

Автор: Akella 3.4.2013, 10:19
http://forum.vingrad.ru/forum/topic-353769.html
Цитата
Например, многие не утруждают себя указать версии библиотек, компонент, версию IDE, ОС.


В D2007 FastMM уже встроен

Добавлено через 1 минуту и 45 секунд
В dpr файле можно добавить строку:
Код
ReportMemoryLeaksOnShutdown := DebugHook <> 0;


http://delphist.ru/utechki-pamyati-v-delphi/

Автор: lollollollol 3.4.2013, 10:28
Akella, извиняюсь за то что тема немного не соответствует названию, и за то что указал не полную информацию.

Я использую делфи7.

По поводу утечки, к сожалению прямо сейчас уже нет времени работать, но вечером обязательно воспользую ссылой.

Спасибо!

Добавлено через 2 минуты и 59 секунд
[Error] hidden.dpr(809): Undeclared identifier: 'ReportMemoryLeaksOnShutdown'

Это откуда?

Автор: Akella 3.4.2013, 10:32
Всё же я бы использовал eurekalog или madExcept

Автор: Poseidon 3.4.2013, 15:22
Цитата(lollollollol @  3.4.2013,  09:06 Найти цитируемый пост)
В результате каждый раз, когда я запрашиваю страничку, диспетчер показывает увеличение памяти. И только увеличение
Хотелось бы выяснить границы видимости переменной buff. Не удивлюсь, если увеличение памяти происходит из-за неочистки этих переменный после отработки.

Автор: lollollollol 3.4.2013, 16:56
buff это просто string, как уже говорилось ранее.
Переменная формируется примерно таким образом:

Код

procedure xxxxxxxxxxxxx(Result:Pointer);
   while (Условие) do begin
      string(result^):=string(result^)+code;
   end;
end;


xxxxxxxxxxxxx(@buff);
send(recvsock,buff[1],length(buff),0);



Автор: Poseidon 3.4.2013, 16:59
Цитата(Poseidon @  3.4.2013,  15:22 Найти цитируемый пост)
Хотелось бы выяснить границы видимости переменной buff.
Если buff и подобные ей переменные глобальные и очищаются только после завершения программы, то нет ничего удивительного в увеличении используемой памяти. string тут вообще не при чем.

Автор: lollollollol 3.4.2013, 17:02
buff не глобальная переменная. Но для записи в неё, я передаю указатель.

Обновил прошлое сообщение.
Может быть проблема в том что я так записываю в функции:

string(result^):=string(result^)+code;

Автор: Чучмек 3.4.2013, 17:05
Цитата(lollollollol @  3.4.2013,  16:56 Найти цитируемый пост)
procedure xxxxxxxxxxxxx(Result:Pointer);
   while (Условие) do begin
      string(result^):=string(result^)+code;
   end;
end;

Что за кака?
Код

procedure xxxxxxxxxxxxx(var S:String);
begin
   while (Условие) do begin
      S:=S+code;
   end;
end;


Автор: lollollollol 3.4.2013, 17:09
Извиняюсь, думал что нельзя так указатели использовать.
А пример подобного кода(как у меня) я вычитал на каком-то форуме.

Автор: Чучмек 3.4.2013, 17:12
Не правильно передаешь строки. Строка имеет внутренний счетчик ссылок. Менеджер памяти освобождает выделенную под строку память, когда счетчик ссылок равен нулю.

Добавлено @ 17:14
Цитата(lollollollol @  3.4.2013,  17:09 Найти цитируемый пост)
думал что нельзя так указатели использовать

Моя невнимательность. var S:string;

Автор: lollollollol 3.4.2013, 17:27
Исправил, всё по прежнему 

Автор: Beltar 3.4.2013, 17:34
Код

procedure xxxxxxxxxxxxx(Result:Pointer);
   while (Условие) do begin
      string(result^):=string(result^)+code;
   end;
end;


 smile 

Никаких пойнтеров к стрингам, если ТОЧНО не знаешь, что делаешь.
Вообще срочно читать учебник для начинающих.

Что мешает по-русски написать?

Код

procedure xxxxxxxxxxxxx(var S:String);
   while (Условие) do begin
      S:=S+code;
   end;
end;


А лучше

Код

function xxxxxxxxxxxxx(const S:String):String;
begin
Result:=S;
{Если число итераций велико, но предел длины результата предсказуем, то можно сразу выделить всю память строке, после цикла укоротить}
   while (Условие) do begin
      Result:=Result+code;
   end;
end;


Автор: Чучмек 3.4.2013, 17:42
Цитата(Beltar @  3.4.2013,  17:34 Найти цитируемый пост)
А лучше

А чем лучше?

Добавлено через 7 минут и 20 секунд
Цитата(lollollollol @  3.4.2013,  17:27 Найти цитируемый пост)
Исправил, всё по прежнему
 А еще подобные конструкции есть.
lollollollol, 
Поставь перед end;
Код

ShowMessage(inttostr(PInteger(PChar(buff)-2*4)^));

Должно выводить единицу.



Автор: lollollollol 3.4.2013, 17:56
От подобных уонструкций избавился, сделал как ты показал. результат


-2054110216


Забыл добавить, код выполняется в потоке, то есть я на каждый запрос браузера выделаю поток. 

Код

    while true do begin
      size := SizeOf(client);
      conn := accept(sock,@client,@size);
      if (conn<>SOCKET_ERROR) then  begin
        ThID:=CreateThread(nil,0,@StartHTTPServer,pointer(conn),0,tid);
        CloseHandle(ThID); //Не помню где, но видел что советуют закрывать хендл потока сразу. Хотел спросить, на сколько это корректно/безопасно?
        sleep(10);
      end;
    end;


И уже в потоке работаю с перменной buff:string;


Делал так:

Код

          buff:=buff+'</body></html>';                                          
          send(recvsock,buff[1],length(buff),0);
          buff:='';
        end;
      end;
    end;
  end;
  Shutdown(recvsock, SD_BOTH);
  closesocket(recvsock);
  ShowMessage(inttostr(PInteger(PChar(buff)-2*4)^)); //-2054110216                                                            
  ExitThread(0);
end;

Автор: Beltar 3.4.2013, 18:12
Тем, что если один возвращаемый параметр, то через функцию банально лучше воспринимается, хотя процедурка тут побыстрее должна быть.

Цитата

ThID:=CreateThread(nil,0,@StartHTTPServer,pointer(conn),0,tid);
        CloseHandle(ThID);


А поток по завершении совершит самоубийство? Если нет, то все, утечка раз дескриптор потерян.

Автор: lollollollol 3.4.2013, 18:19
Beltar, даже если так не делать, ничего не меняет, проверил. и утечка таже, и -2054110216  

Автор: Beltar 3.4.2013, 18:33
Ты вызываешь ф-ию WinAPI, ее утечки дельфовым менеджером памяти не отловить. Можно MemProof по пробовать.
По алгоритму отладчик в помощь, но сначала переписать все без указателей.

Автор: Чучмек 3.4.2013, 18:36
Цитата(lollollollol @  3.4.2013,  18:19 Найти цитируемый пост)
и -2054110216   

Это нормально. Это из за
Цитата(lollollollol @  3.4.2013,  17:56 Найти цитируемый пост)
 buff:='';

Здесь не должно быть больше 1.
Твоя проблема в потоках.
ExitThread не возвращает управление. Соответственно не выполняется код, который добавляет делфа для освобождения строк, по завершении функции.

Добавлено @ 18:38
Закоментируй строку
Цитата(lollollollol @  3.4.2013,  17:56 Найти цитируемый пост)
 ExitThread(0);
, и проверь

Добавлено @ 18:44
Сделай так:
Код

procedure MyProc;
var
  s1,
  s2,
  sn:string;
begin
{ здесь работа со строкам }
end;

function ThtradProc(p:pointer):cardinal;stdcall;
begin
  MyProc;
  ExitThread(0);
end;
 

Автор: lollollollol 3.4.2013, 18:57
Чучмек, спасибо!!!

Закоментировал строку
Код

ExitThread(0);


и утечка пропала. память возвращает в норму, прям до байтика!


Вот уж не думал что проблема в этом... Огромное спасибо!

Добавлено через 9 минут и 58 секунд
Интересует вопрос. Всё ли корректно с потоком, если не вызывать ExitThread(0);,
и не повредит ли закрытие хендла сразу после создания потока?

Не смог найти статью, но читал что такое действие спасает от утечки при завершении потока.

Автор: Чучмек 3.4.2013, 20:25
Цитата(lollollollol @  3.4.2013,  18:57 Найти цитируемый пост)
Интересует вопрос. Всё ли корректно с потоком, если не вызывать ExitThread(0);,

Во первых решается.
Цитата(Чучмек @  3.4.2013,  18:36 Найти цитируемый пост)
Сделай так:

Во вторых - корректно.
Код

ExitThread(0);
 эквивалентно
Код

result:=0;

http://vsokovikov.narod.ru/New_MSDN_API/Process_thread/fn_threadproc.htm
Цитата(lollollollol @  3.4.2013,  18:57 Найти цитируемый пост)
и не повредит ли закрытие хендла сразу после создания потока?

Не повредит.
Цитата

Объект потока остается в системе, до тех пор, пока не поток закончит работу, и все дескрипторы к нему не будут закрыты через вызов CloseHandle.

http://vsokovikov.narod.ru/New_MSDN_API/Process_thread/fn_createthread.htm

Автор: lollollollol 3.4.2013, 20:50
Цитата

Сделай так:

Я сразу так сделал, как увидел Ваше сообщение.

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

Я знаю что в системе есть ограничение на потоки для одного процесса.
И если буду висеть примерно 2000 объектов потоков, то новые потоки созданы не будут.



P.S. Думаю тему будет разумно переименовать в Утечка памяти, String, Потоки
или что нибудь подобное, чтобы люди могли найти решение

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)