Эти странные динамические строки

Clarion, Clarion 7

Модератор: Дед Пахом

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
PavelNK
Старожил
Сообщения: 262
Зарегистрирован: 15 Март 2011, 8:02

Эти странные динамические строки

Сообщение PavelNK »

Игорь Столяров писал(а): 26 Октябрь 2018, 16:08
vic7tar писал(а): 25 Октябрь 2018, 15:56С DynStr не имел дела, но напрашивается вопрос
А напрасно ! Прелюбопытнейший прибамбас, доложу я Вам … :)

Зацикливаем, например вот такой код и смотрим через диспетчер задач, как приложение медленно,
но верно начинает поджирать память:

Код: Выделить всё


  Loop ...
     MySlip &= NewDynStr()
     MySlip.Cat('Какой-то длинный предлинный текст')
     !!! MySlip.Kill
     DisposeDynStr(MySlip)
  end
  
Убираем комментарий и всё приходит в норму - расход памяти на уровне погрешности наблюдения (плюс / минус)…
Почему оно всё так сделано ? Это вопрос грустной философии Clarion … ;)
Все просто.
IDynStr - это интерфейс, а не класс. Т.е. он содержит только методы, а свойств не содержит.
Т.к. это не класс, то у него нет ни конструктора, ни деструктора, которые бы запускались при создании и удалении объекта.
Но где-то внутри есть, по крайней мере одна, переменная, которая содержит адрес динамической строки.
При вызове DisposeDynStr(MySlip) освобождается только память выделенная под этот объект, но не происходит освобождения памяти переменных выделенных при работе класса. Поэтому память выделенная под строку не освобождается.

Самым лучшим выходом мне видится написание класса, наследованного от данного интерфейса, в деструкторе которого нужно вызвать метод Kill, тогда при вызове Dispose для объекта этого класса будет автоматически запускаться деструктор.

А еще лучше объявлять не ссылку на класс, а класс. Тогда, при выходе из процедуры, будет автоматически запускаться деструктор и не будет необходимости помнить об освобождении памяти выделенных в классе, а также и памяти выделенной под сам класс.
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

PavelNK писал(а): 26 Октябрь 2018, 20:07не будет необходимости помнить об освобождении памяти выделенных в классе
Не согласный я с этим !
Если там где то внутри есть указатель по которому выделяется память через New() - то без ЯВНОГО Dispose() она зависнет.
Очень похоже, что именно поэтому DisposeDynStr() и выполняет чистку. А как оно там на самом деле - не ведомо никому.
За теми кто отстал - не возвращаться. (С) Кодекс
PavelNK
Старожил
Сообщения: 262
Зарегистрирован: 15 Март 2011, 8:02

Эти странные динамические строки

Сообщение PavelNK »

Игорь Столяров писал(а): 26 Октябрь 2018, 20:26
PavelNK писал(а): 26 Октябрь 2018, 20:07не будет необходимости помнить об освобождении памяти выделенных в классе
Не согласный я с этим !
Если там где то внутри есть указатель по которому выделяется память через New() - то без ЯВНОГО Dispose() она зависнет.
Очень похоже, что именно поэтому DisposeDynStr() и выполняет чистку. А как оно там на самом деле - не ведомо никому.
Можно соглашаться, можно не соглашаться.
Но критерий истины практика.
Попробуй создай свой интерфейс.
А потом создай класс так, как я написал.
И все поймешь, ты все увидишь сам.
PavelNK
Старожил
Сообщения: 262
Зарегистрирован: 15 Март 2011, 8:02

Эти странные динамические строки

Сообщение PavelNK »

Можешь создать класс, в котором объявить два указателя на строки.
Один освобождать в деструкторе, а другой - нет.
И память будет пропадать.
Аватара пользователя
vic7tar
Ветеран
Сообщения: 365
Зарегистрирован: 09 Февраль 2017, 20:12

Эти странные динамические строки

Сообщение vic7tar »

PavelNK писал(а): 26 Октябрь 2018, 20:07При вызове DisposeDynStr(MySlip) освобождается только память выделенная под этот объект, но не происходит освобождения памяти переменных выделенных при работе класса. Поэтому память выделенная под строку не освобождается.
Да все там вроде освобождается, думаю, что надо просто после DisposeDynStr ставить обычный Dispose и тут же про все забывать.
А кто подскажет, а что делает Release?
C10, Win10x64
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

vic7tar писал(а): 27 Октябрь 2018, 6:17ставить обычный Dispose
Да как-то очкую я применять к разрушенному указателю Dispose() после DisposeDynStr() … :(
Тем более что в справке явно сказано, что такое действие приводит к GPF ...
Знать бы как оно по науке надо делать, так сказать по замыслу создателя сего, а не методом тыка …
vic7tar писал(а): 27 Октябрь 2018, 6:17А кто подскажет, а что делает Release?
Ну судя по тому, что делает метод Kill(), то первое, что приходит в голову про метод Release() - надо считать неверным. ;)

Если бы я делал такой класс работы со строками, то при уменьшении длины строки (Kill, Trunk)- не уменьшал бы буфер,
а просто переносил бы признак конца строки Chr(0) в нужное место. Возможно Release() как раз освобождает именно буфер
памяти под строку …

А может быть и с точностью до наоборот. Kill() - освобождает буфер памяти, а Release() - "обнуляет" строку в буфере.
Это хоть как-то бы объяснило феномен с Kill & DisposeDynStr описанный мною ниже … и по названиям логично выглядит.
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
vic7tar
Ветеран
Сообщения: 365
Зарегистрирован: 09 Февраль 2017, 20:12

Эти странные динамические строки

Сообщение vic7tar »

Игорь Столяров писал(а): 27 Октябрь 2018, 6:36Тем более что в справке явно сказано, что такое действие приводит к GPF ...
Где можно найти эту справку?
C10, Win10x64
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

vic7tar писал(а): 27 Октябрь 2018, 7:15Где можно найти эту справку?
В справке к Clarion, описание оператора Dispose(). Есть на английском, есть на русском - как Вам удобней.
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
vic7tar
Ветеран
Сообщения: 365
Зарегистрирован: 09 Февраль 2017, 20:12

Эти странные динамические строки

Сообщение vic7tar »

Я имел ввиду справку на DynStr. Имеется ввиду малюсенький help-ик?
C10, Win10x64
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

Я ведь не знаю что Вы имеете ввиду …
В моём сообщении явно написано, что применение Dispose() к разрушенному указателю приводит к GPF.

Маленькая справка на русском по IDynStr - это самопал, а не перевод. Я фирменной документации по IDynStr не знаю … :(
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
vic7tar
Ветеран
Сообщения: 365
Зарегистрирован: 09 Февраль 2017, 20:12

Эти странные динамические строки

Сообщение vic7tar »

Для себя определил примерно такую схему, если понадобится в будущем:

Код: Выделить всё

DS     &IDynStr
cs1    &Cstring
cs2    &Cstring
rez    &Cstring
ncs    Long

    code
        ncs = 20
        cs1 &= new Cstring(ncs + 1)
        cs2 &= new Cstring(ncs + 1)
        loop i# = 1 to ncs
            cs1[i#] = '#'
            cs2[i#] = '*'
        end  
       
        DS &= NewDynStr()
        
        DS.Cat(cs1)
        DS.Cat(cs2)

        rez &= new Cstring(DS.StrLen() + 1)
        rez = DS.CSTR()   ! или DS.CopyTo(rez) 

        DS.Kill()

        DisposeDynStr(DS)
        Dispose(DS)
        Dispose(cs1)
        Dispose(cs2)
        Dispose(rez)
        
Проверял на больших строках при просмотре оперативки -> все правильно создается и правильно уничтожается.
Остался для меня открытым вопрос о Release.
C10, Win10x64
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

Это всё очень и очень здорово … в десятистрочном тесте. ;)

1. Нет никаких обоснований для применения Dispose(DS) после DisposeDynStr(DS).
Как говорил Портос: "А я дерусь … потому что дерусь !" :)

2. Никак не решён вопрос с определением инициализации DS.
В большом объёме кода с кучей процедур и методов Вы не определите нужно ли применять DisposeDynStr(DS)
к динамической строке по завершению работы, да и вообще, можно ли с ней работать.

3. Kill() перед DisposeDynStr(DS) - это примерно как Clear() перед Dispose() для обычной строки.
Не знаю чем руководствовались Вы добавляя его, например я - просто методом тыка нашёл что позволяет избежать утечки памяти. :)
Почему так происходит и каков правильный механизм работы с динамическими строками ? Неведомо !

4. Тогда о чём этот пример ? Вы показали некий вариант, который вроде бы не валится при работе ? ;)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
vic7tar
Ветеран
Сообщения: 365
Зарегистрирован: 09 Февраль 2017, 20:12

Эти странные динамические строки

Сообщение vic7tar »

Игорь Столяров писал(а): 27 Октябрь 2018, 11:231. Нет никаких обоснований для применения Dispose(DS) после DisposeDynStr(DS).
Привычка не оставлять за собой следов - без Dispose(DS) ненулевая ссылка на DS будет еще существовать и указывать на уже уничтоженный объект.
Игорь Столяров писал(а): 27 Октябрь 2018, 11:23... нужно ли применять DisposeDynStr(DS)
к динамической строке по завершению работы, да и вообще, можно ли с ней работать.
DisposeDynStr(DS) как раз и уничтожает строку.
Игорь Столяров писал(а): 27 Октябрь 2018, 11:23Kill() перед DisposeDynStr(DS) ...
Забыл убрать.
Игорь Столяров писал(а): 27 Октябрь 2018, 11:23 например я - просто методом тыка нашёл что позволяет избежать утечки памяти. :)
А здесь поподробнее - какие там утечки памяти и что Вы там нашли методом тыка?
Игорь Столяров писал(а): 27 Октябрь 2018, 11:23 Тогда о чём этот пример ? Вы показали некий вариант, который вроде бы не валится при работе ? ;)
Смотрим внимательно начало темы. :idied:
C10, Win10x64
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7330
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Эти странные динамические строки

Сообщение Игорь Столяров »

vic7tar писал(а): 27 Октябрь 2018, 12:19Смотрим внимательно начало темы.
Согласен с Вами. Это скорее не вопрос, а приглашение к обсуждению. Здесь может быть много разного.
vic7tar писал(а): 27 Октябрь 2018, 12:19какие там утечки памяти
Забудьте пожалуйста. Это была просто шутка. На самом деле всё хорошо. :)
За теми кто отстал - не возвращаться. (С) Кодекс
Yufil
Ветеран движения
Сообщения: 1277
Зарегистрирован: 16 Май 2006, 14:34
Контактная информация:

Эти странные динамические строки

Сообщение Yufil »

1.
По-моему, проще юзать Any, её можно пользовать просто как строку, а можно - как ссылку на строку, по вкусу.
Но хотя бы работают стандартные строковые функции Клариона.

2.
Возьми Cstr.zip из соседнего топика

S Cstr ! S.Len - длина, S.S - сама строка ( &Cstring )
Rez Cstr
.....
S.Set('12345') ! S.Len = 5, S.S='12345'
S.Cat( '6789') ! S.Len = 9, S.S='123456789'
Rez.Set( S.S & 'text' ) ! Присвоение подстроки
S.SaveToFile( 'File.txt' ) ! Записали в файл
S.LoadFromFile( 'File.txt' ) ! Прочитали из файла
S.ToUtf8() ! Перекрутили в UTF-8
..... ну и так далее ....
Деструктор уберёт объекты S и Rez по концу области видимости. Да, все манипуляции над строками используют WinApi -
при работе с длинными строками была приличная экономия в скорости. Можно и нулевые байты включать в строку,
тогда надо или пользоваться методом Str() или просто вырезкой S.S[ 1: S.Len ]

С прошлого тысячелетия живёт, каши не просит...
Ответить