Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Динамическое создание строк


Страницы:   1 2 3 4

Skier ©   (2002-06-26 13:18:00) 

Господа, мне нужно динамически создавать строки
(не PChar, а именно String(!) )

Я делаю что-то вроде этого :

.......................
type
PString = ^String;
var
AStr := AllocMem(4);
AStr^ := "hello, world !"
FreeMem(AStr, 4);
.......................

Вроде бы всё работает, но что-то меня
терзают смутные сомненния : не происходит ли memory leak ?
И вообще как это всё лучше всего делать ?


Kaban   (2002-06-26 16:13:00) [21]

2McSimm
>(Тов. Фарфуркис - устраните :)

а ник у тебя часом не оттуда же :-)


valery_f   (2002-06-26 16:12:00) [22]

Только что глянул в отладчике - при выходе из процедуры локальная строка уничтожается через LStrClr. На входе у LStrClr - строка, т.е. указатель. Грубо говоря, LStrClr вычитает из этого адреса восемь байт (судя по всему - размер служебной информации) и уже для этого адреса зовет FreeMem. Так что звать FreeMem для самой строки (т.е. исходного указателя) - дохлый номер (в смысле - Access violation :)

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


McSimm   (2002-06-26 16:10:00) [23]

>valery_f (26.06.02 15:55)
Тут маленькое недоразумение. (Тов. Фарфуркис - устраните :)

FreeMem( указатель) освобождает выделенные 4 байта памяти потому что указательбыл получен как AllocMem(4); Именно эти 4 байта (а не 4 байта указателя) и будут возвращены куче. А что в этих 4х байтах хранилось - неважно.

Так понятнее?

>А если для освобождения строки использовать
>Finalize ?
Можно. А можно использовать New-Dispose - в этой связке Finalize уже есть


Skier   (2002-06-26 16:09:00) [24]

> Толик

"Насчёт счётчик а ссылок в строках - он есть только в
ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю)"

IMHO,путаешь.
У Марко Канту в книжке был пример про кол-во ссылок к строке.


Толик   (2002-06-26 16:04:00) [25]

Прошу прощения, что вмешиваюсь в столь активную беседу (очень уж интересная получается!) и посмею высказать своё мнение. Раз уж нужно формировать строки динамически, то может быть всё-таки использовать указатель на массив символов, а потом, в нужных местах заниматься приведением к типу string? Так ведь проще... Насчёт счётчика ссылок в строках - он есть только в ansistring а в string есть только размер и сами символы (если я конечно ничего не путаю). Так что моё мнение - использовать pchar + приведение типов (оно ведь память не выделяет, по крайней мере не должно).


Skier   (2002-06-26 15:58:00) [26]

>McSimm
А если для освобождения строки использовать
Finalize ?

Т.е.


type
TMyRec = String;
PMyRec = ^TMyRec;
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
AMyRec^ := "hello, world !";
Finalize(AMyRec^);
FreeMem(AMyRec, SizeOf(TMyRec));
end;

?????????


valery_f   (2002-06-26 15:55:00) [27]

> McSimm © (26.06.02 15:30)
> FreeMem(указатель) освобождает выделенные 4 байта памяти

Ты хоть сам-то понял что сказал? Освобождается память !по адресу! записанному в указателе, а сам указатель (размером 4 байта) от этого никак не меняется.

> На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Как это безразлично? Все выделенные куски памяти значатся в таблице, именно поэтому FreeMem не требует указания размера освобождаемой памяти - оно известно. Попробуй сделать FreeMem левого указателя - не знаю что там у тебя, а у меня Access violation...


McSimm   (2002-06-26 15:50:00) [28]

сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
Разумеется SizeOf(TMyRec).

Кстати, обратите внимание, Если элементом TMyRec будет строка, то FreeMem(AMyRec) не освободитпамять от строки! только от AMyRec


Skier   (2002-06-26 15:41:00) [29]

> Игорь Шевченко
Это как раз понятно.


Skier   (2002-06-26 15:39:00) [30]

> McSimm
Т.е. на сколько я понял подсчёт ссылок ведётся только
тогда когда строка создаётся самой Delphi

var
AStr : String;
//и т.д.

Или можно как-то ещё заставить Delphi считать ссылки ?

"FreeMem(указатель) освобождает выделенные 4 байта памяти в куче."

Мне кажеться что это не так, допустим :

type
TMyRec = packed record
mrField1 : Integer;
mrField1 : Integer;
end;
PMyRec = ^TMyRec
var
AMyRec : PMyRec;
begin
AMyRec := AllocMem(SizeOf(TMyRec));
//работа с AMyRec
FreeMem(AMyRec);
//сколько FreeMem освободит? 4 или SizeOf(TMyRec) байт ??
end;



Игорь Шевченко   (2002-06-26 15:32:00) [31]

Если имеется локальная(ые) переменная типа String
то генерируется код:
begin
try
... тело процедуры
finally
_LStrClr(локальнаяпеременнаяString);
end;
end; { Процедуры }


McSimm   (2002-06-26 15:30:00) [32]

Тут достаточно понять такую штуку.

FreeMem( указатель) освобождает выделенные 4 байта памяти в куче.
На что указывал этот указатель и были ли эти 4 байта указателем вообще - процедуре FreeMem безразлично.

Соответственно то что скрывается за указатель^становится сиротой, если только нет других на это ссылок.

Вот пример.

S := DateToStr(Now);
AStr := @S;
FreeMem(AStr);

строка с датой проживет ровно столько, сколько проживет переменная S. И FreeMem не помешает.

Если же то же самое без переменной S - то строка будет имеет статус локальной переменной с минимальным сроком жизни. И опять же никак не зависит от FreeMem.


Skier   (2002-06-26 15:19:00) [33]

>McSimm
Это понятно.
Когда я писал "код ошибочен"
я имел в виду не будет ли утечки памяти.

Т.е. меня очень интересовала "внутреняя работа Delphi со
строками". (выделение памяти, подсчёт ссылок и освобождение памяти).


McSimm   (2002-06-26 15:12:00) [34]

Чтобы понятнее было почему компилятор не должен освобождать строку, можно проделать такой опыт:

AStr := AllocMem(4);
// AStr^ := "hello, world !";
Pointer(AStr^) := Pointer(123456); // произвольные 4 байта
FreeMem(AStr, 4);

Ошибки нет. Все будет работать. Только потому, что программа не будет пытаться освободить строку по отфонарному адресу


Skier   (2002-06-26 15:11:00) [35]

> McSimm
А всё-таки ?

А если это будет не строка а скажем Varinant и
будет использоваться соотв-но
PVariant = ^Varinant, будет тоже самое или как ??
(Имею в виду memory leak)


McSimm   (2002-06-26 15:04:00) [36]

Смотря как посмотреть :)

Собственно ошибки тут нет.
AStr^ := ""; - корректно освободит память от строки
FreeMem - освободит память от указателя


Skier   (2002-06-26 14:53:00) [37]

> McSimm
Т.е. код ошибочен, даже если
писать

AStr^ := "hello, world !";
AStr^ := "";

??????


Viewer   (2002-06-26 14:42:00) [38]

Я уже предложил вопрошающему проверку.
Viewer (26.06.02 14:02)

При s:="" память очень даже освобождается и в Win98

>valery_f (26.06.02 14:35)
>Во всяком случае, по результатам тестов дельфи делает VB, C#, >VC++ и Intel C++ по скорости

Вот здесь не надо ля-ля. На строках именно паскаль и тормозит.


McSimm   (2002-06-26 14:40:00) [39]

Все немножко (самую малость) сложнее. Попробую объяснить.
Как я уже написал,
> тут все зависит от того способа каким это строка создана


Для начала необходимо понять, что FreeMem и освобождение памяти от строки - не связаны. Т.е. могут быть случаи, когда строка будет освобождена даже если вы не освобождаете AStr. И наоборот.

AStr - указатель на выделенный блок памяти 4 байта.
В этих четырех байтах хранится указательна строку.

Конкретно в приведенном примере AStr^ := "hello, world !"
вообще не будет выделяться память под строку - она уже есть в сегменте данных и AStr^ просто получит на нее указатель.

В другом случае, напр. AStr^ := IntToStr(12345) будет создана строка "12345" динамически, но счетчик испоьзования увеличен не будет, сколько указателей на нее бы не ссылались. Строка будет уничтожена компилятором при выходе из процедуры, не зависимо от того освободите ли вы память от указателей или нет.


valery_f   (2002-06-26 14:35:00) [40]

Насколько я помню, переменная типа string - это указатель на выделенную память. От этого адреса в "плюс" идет строка с нулем в конце (т.е. переменную можно использовать как PChar), а в обратную - служебная информация, включая длину строки и пр. (состав и формат служ. информации зависит от версии). Видимо там же расположен и счетчик ссылок.

Что касается освобождения памяти, то этим занимается дельфийский "сборщик мусора", т.е. s:="" память, скорее всего, мгновенно не освободит. Однако заморачиваться по этому поводу не стОит, т.к. этих "сборщиков" - целая куча и в винде (к примеру - высвобождение хэндлов после обнуления счетчика ссылок на них), и в дельфи (строки, COM-объекты и пр.) и всё пока что работает. Во всяком случае, по результатам тестов дельфи делает VB, C#, VC++ и Intel C++ по скорости и качеству работы с памятью.


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо