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

Clarion, Clarion 7

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

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

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

Сообщение PavelNK » 26 Октябрь 2018, 20:07

Игорь Столяров писал(а):
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 для объекта этого класса будет автоматически запускаться деструктор.

А еще лучше объявлять не ссылку на класс, а класс. Тогда, при выходе из процедуры, будет автоматически запускаться деструктор и не будет необходимости помнить об освобождении памяти выделенных в классе, а также и памяти выделенной под сам класс.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 26 Октябрь 2018, 20:26

PavelNK писал(а):
26 Октябрь 2018, 20:07
не будет необходимости помнить об освобождении памяти выделенных в классе
Не согласный я с этим !
Если там где то внутри есть указатель по которому выделяется память через New() - то без ЯВНОГО Dispose() она зависнет.
Очень похоже, что именно поэтому DisposeDynStr() и выполняет чистку. А как оно там на самом деле - не ведомо никому.
«V» значит Вендетта !

PavelNK
Старожил
Сообщения: 216
Зарегистрирован: 15 Март 2011, 8:02

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

Сообщение PavelNK » 26 Октябрь 2018, 20:32

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

PavelNK
Старожил
Сообщения: 216
Зарегистрирован: 15 Март 2011, 8:02

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

Сообщение PavelNK » 26 Октябрь 2018, 20:34

Можешь создать класс, в котором объявить два указателя на строки.
Один освобождать в деструкторе, а другой - нет.
И память будет пропадать.

Аватара пользователя
vic7tar
Активист
Сообщения: 150
Зарегистрирован: 09 Февраль 2017, 20:12

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

Сообщение vic7tar » 27 Октябрь 2018, 6:17

PavelNK писал(а):
26 Октябрь 2018, 20:07
При вызове DisposeDynStr(MySlip) освобождается только память выделенная под этот объект, но не происходит освобождения памяти переменных выделенных при работе класса. Поэтому память выделенная под строку не освобождается.
Да все там вроде освобождается, думаю, что надо просто после DisposeDynStr ставить обычный Dispose и тут же про все забывать.
А кто подскажет, а что делает Release?
C10, Win10x64

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 27 Октябрь 2018, 6:36

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 описанный мною ниже … и по названиям логично выглядит.
«V» значит Вендетта !

Аватара пользователя
vic7tar
Активист
Сообщения: 150
Зарегистрирован: 09 Февраль 2017, 20:12

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

Сообщение vic7tar » 27 Октябрь 2018, 7:15

Игорь Столяров писал(а):
27 Октябрь 2018, 6:36
Тем более что в справке явно сказано, что такое действие приводит к GPF ...
Где можно найти эту справку?
C10, Win10x64

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 27 Октябрь 2018, 7:22

vic7tar писал(а):
27 Октябрь 2018, 7:15
Где можно найти эту справку?
В справке к Clarion, описание оператора Dispose(). Есть на английском, есть на русском - как Вам удобней.
«V» значит Вендетта !

Аватара пользователя
vic7tar
Активист
Сообщения: 150
Зарегистрирован: 09 Февраль 2017, 20:12

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

Сообщение vic7tar » 27 Октябрь 2018, 7:36

Я имел ввиду справку на DynStr. Имеется ввиду малюсенький help-ик?
C10, Win10x64

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 27 Октябрь 2018, 7:43

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

Маленькая справка на русском по IDynStr - это самопал, а не перевод. Я фирменной документации по IDynStr не знаю … :(
«V» значит Вендетта !

Аватара пользователя
vic7tar
Активист
Сообщения: 150
Зарегистрирован: 09 Февраль 2017, 20:12

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

Сообщение vic7tar » 27 Октябрь 2018, 10:52

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

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

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

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 27 Октябрь 2018, 11:23

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

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

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

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

4. Тогда о чём этот пример ? Вы показали некий вариант, который вроде бы не валится при работе ? ;)
«V» значит Вендетта !

Аватара пользователя
vic7tar
Активист
Сообщения: 150
Зарегистрирован: 09 Февраль 2017, 20:12

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

Сообщение vic7tar » 27 Октябрь 2018, 12:19

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

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 3806
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-Дону

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

Сообщение Игорь Столяров » 27 Октябрь 2018, 13:42

vic7tar писал(а):
27 Октябрь 2018, 12:19
Смотрим внимательно начало темы.
Согласен с Вами. Это скорее не вопрос, а приглашение к обсуждению. Здесь может быть много разного.
vic7tar писал(а):
27 Октябрь 2018, 12:19
какие там утечки памяти
Забудьте пожалуйста. Это была просто шутка. На самом деле всё хорошо. :)
«V» значит Вендетта !

Yufil
Ветеран движения
Сообщения: 1070
Зарегистрирован: 16 Май 2006, 13:34
Контактная информация:

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

Сообщение Yufil » 28 Октябрь 2018, 21:46

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 ]

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

Ответить