При распределении строки добавляется ещё 15 лишних байт. Строка может быть переприсвоена. Если новая строка помещается в эти старые n байт + 15 байт резерва, то перераспределения не происходит. Если же не помещается, то производится перераспределение с добавлением к новой длине 15 байт.
Как же вы записываете тогда в поле len максимальную длину строки?
И если вы выбираете размер буфера максимальный то и размер строки
тоже видимо ограничивается максимальным значением строки.
Надо глянуть в доке по MQL4. Но если такого ограничения нет то
максимальный размер видимо указывается как MAX_INT
Максимальный размер буфера модифицируется в рантайме, когда
происходят операции со строками. Ограничение выставляется
экономно, но с запасом.
То есть в рантайме когда в эксперте присваивается новое значение
строке, то терминал анализирует её длину и если new string length >
(old string length + 15 byte) то вы делаете буфер равным (new string length + 15 byte).
Но это происходит только в эксперте, если записываем новую строку,
а если в длл то длина новой строки должна быть не больше буфера
+ 15 на момент её передачи в функцию длл. Всё это понял.
Ещё хотел поинтересоваться. Насущный вопрос. Я делаю в эксперте
импорт функций и думаю что она загружается динамически (в отладчике длл это
заметил).
Но при удалении эксперта с чарта (на одном чарте только разместил
эксперта) и при удалении его с чарта длл не освобождается иногда
и остаётся занятой терминалом пока терминал не закрою. Хотел
узнать при удалении терминала с чарат и если длл была загружена
динамически то вызывается ли FreeLibrary?
Хм тогда очень странно почему иногда файл библиотеки не освобождался
терминалом для того чтобы его заменить новой версией. Ещё потестирую
с этим может быть проблема больше не возникет. Или она возникает
когда запускаю отладку длл или дебаг версию длл размещаю в папку
libraries в терминале.
Положу релиз версию в эту папку и потестирую на освобождения
длл для записи новой версией.
elritmo:
Хм тогда очень странно почему иногда файл библиотеки не освобождался
терминалом для того чтобы его заменить новой версией. Ещё потестирую
с этим может быть проблема больше не возникет. Или она возникает
когда запускаю отладку длл или дебаг версию длл размещаю в папку
libraries в терминале.
Положу релиз версию в эту папку и потестирую на освобождения
длл для записи новой версией.
Может библиотека еще где-то использовалась? Тестер, другие окна
и тд.
Renat, в вашем примере, функция GetStringValue описана как MT4_EXPFUNC char* __stdcall GetStringValue(char *spar) (т.е. возвращает pchar)
Вызов ее выполняется как string sret; sret=GetStringValue("some string");
Посему возникают вопросы:
Что произодет со структурой MqlStr? Т.е. в data записывается возвращаемый pchar, а что произойдет с полем len, туда запишется длина вернувшейся строки (а как быть со строками в сегменте .data)? Что произойдет, если в эту строку в дальнейшем будет запись строки бОльшего размера - должно ж ведь произойти реаллоцирование памяти, а если у вас собственный memory manager, то ведь будут проблемы, или память выделяется средствами win api? Будет ли освобождена память вернувшейся строки, когда, и через какую функцию?
Я это все к тому, что я могу выделить память под строку разными способами - это и делфевский GetMem, который использует собственный ММ, и api-шные VirtualAlloc/GlobalAlloc/HeapAlloc, и вернуть ссылку на статические данные как pchar, и как вы ее потом собираетесь освобождать? Хотелось бы, чтобы вы озвучили механизм как надо делать (о чем вас просят уже довольно долго ;), но тема до сих пор не раскрыта). В вашем примере, внутри GetStringValue, возвращаемая строка не аллоцируется (поэтому пример можно назвать неудачным).
Мы просто скопируем строку из Вашего буфера в _свою_ строку, с выделением в _своем_ пуле. А потом Ваша строка нас не интересует. То есть, если Вы дадите нам динамическую (через выделение памяти) строку, а потом сами не позаботитесь об ее отслеживании и удалении, то получите серьезнейшую утечку памяти.
Что рекомендуется делать:
не возвращать никаких строк в MQL4, а заполнять строки, переданные в параметрах
если возвращать, то выдавать ссылки на статические буферы (не в стеке!) или из своего собственного контролируемого пула с четким пониманием, что любая выданная "наверх" строка становится неконтролируемой до конца работы.
Что еще важно - если пишете в DLL функции, которые вызываются миллионы раз (а это происходит в тестере), то минимизируйте количество перевыделений памяти. Никаких массовых new/delete на каждом вызове. Не фрагментируйте память процесса своими массовыми перевыделениями. Мы в разы ускорили тестер и MQL4, избавившись от множественных перевыделений памяти.
ps: забудьте запись/модификацию параметра len - Вас вообще не должен он волновать. Вы можете только читать и все. Что туда писать решает среда выполнения MQL4.
Спасибо, Renat, после трех страниц топа я все таки выжал из вас инфу :D
Хотя из всего этого следует один неутешительный вывод - свой pchar вернуть нельзя (а если и вернуть, то как его потом освобождать?), можно только переписывать буфер переданной строки (что вы и описали в ваших рекомендациях).
Может вам имеет смысл написать статью про весь этот механизм? А то данный топ потеряется в архивах, а вопросы останутся...
з.ы. Хотелось бы, чтобы в mql4 была функция задания длины строки (типа SetLength), по крайней мере в хелпе не нашел, т.к. сейчас приходится формировать ее в цикле типа for (int i=1; i<=MaxStringLength; i++) MaxString = MaxString + " ";
С учетом того, что вы озвучили, что реалллокейт строки происходит по 15 символов - можно оптимизировать, но это все равно как то через задницу - мой мозг оптимизатора (в чем мы с вами похожи) такой вариант воспринимает с трудом :)
Как же вы записываете тогда в поле len максимальную длину строки? И если вы выбираете размер буфера максимальный то и размер строки тоже видимо ограничивается максимальным значением строки. Надо глянуть в доке по MQL4. Но если такого ограничения нет то максимальный размер видимо указывается как MAX_INT
Ещё хотел поинтересоваться. Насущный вопрос. Я делаю в эксперте импорт функций и думаю что она загружается динамически (в отладчике длл это заметил).
Но при удалении эксперта с чарта (на одном чарте только разместил эксперта) и при удалении его с чарта длл не освобождается иногда и остаётся занятой терминалом пока терминал не закрою. Хотел узнать при удалении терминала с чарат и если длл была загружена динамически то вызывается ли FreeLibrary?
FreeLibrary вызывается при выгрузке эксперта, вызвавшего функцию из этой библиотеки.
Положу релиз версию в эту папку и потестирую на освобождения длл для записи новой версией.
Хм тогда очень странно почему иногда файл библиотеки не освобождался терминалом для того чтобы его заменить новой версией. Ещё потестирую с этим может быть проблема больше не возникет. Или она возникает когда запускаю отладку длл или дебаг версию длл размещаю в папку libraries в терминале.
Положу релиз версию в эту папку и потестирую на освобождения длл для записи новой версией.
MT4_EXPFUNC char* __stdcall GetStringValue(char *spar)
(т.е. возвращает pchar)
Вызов ее выполняется как
string sret;
sret=GetStringValue("some string");
Посему возникают вопросы:
Что произодет со структурой MqlStr?
Т.е. в data записывается возвращаемый pchar, а что произойдет с полем len, туда запишется длина вернувшейся строки (а как быть со строками в сегменте .data)?
Что произойдет, если в эту строку в дальнейшем будет запись строки бОльшего размера - должно ж ведь произойти реаллоцирование памяти, а если у вас собственный memory manager, то ведь будут проблемы, или память выделяется средствами win api?
Будет ли освобождена память вернувшейся строки, когда, и через какую функцию?
Я это все к тому, что я могу выделить память под строку разными способами - это и делфевский GetMem, который использует собственный ММ, и api-шные VirtualAlloc/GlobalAlloc/HeapAlloc, и вернуть ссылку на статические данные как pchar, и как вы ее потом собираетесь освобождать?
Хотелось бы, чтобы вы озвучили механизм как надо делать (о чем вас просят уже довольно долго ;), но тема до сих пор не раскрыта).
В вашем примере, внутри GetStringValue, возвращаемая строка не аллоцируется (поэтому пример можно назвать неудачным).
Что рекомендуется делать:
Что еще важно - если пишете в DLL функции, которые вызываются миллионы раз (а это происходит в тестере), то минимизируйте количество перевыделений памяти. Никаких массовых new/delete на каждом вызове. Не фрагментируйте память процесса своими массовыми перевыделениями. Мы в разы ускорили тестер и MQL4, избавившись от множественных перевыделений памяти.
ps: забудьте запись/модификацию параметра len - Вас вообще не должен он волновать. Вы можете только читать и все. Что туда писать решает среда выполнения MQL4.
Хотя из всего этого следует один неутешительный вывод - свой pchar вернуть нельзя (а если и вернуть, то как его потом освобождать?), можно только переписывать буфер переданной строки (что вы и описали в ваших рекомендациях).
Может вам имеет смысл написать статью про весь этот механизм?
А то данный топ потеряется в архивах, а вопросы останутся...
з.ы. Хотелось бы, чтобы в mql4 была функция задания длины строки (типа SetLength), по крайней мере в хелпе не нашел, т.к. сейчас приходится формировать ее в цикле типа
for (int i=1; i<=MaxStringLength; i++) MaxString = MaxString + " ";
С учетом того, что вы озвучили, что реалллокейт строки происходит по 15 символов - можно оптимизировать, но это все равно как то через задницу - мой мозг оптимизатора (в чем мы с вами похожи) такой вариант воспринимает с трудом :)