Понятно, что рекурсия сама по себе потребляет большее количество стековой памяти, но потребление это прямо пропорционально количеству вызовов и пиковое потребление памяти, если таковых вызовов много, может быть весьма существенным. Здесь все совсем по другому, область памяти занятая под стек если и должна увеличится, то только первый раз, так чтобы разместить все вызовы. Но она растет раз за разом. Стек здесь не причем, ибо указатель стека ESP возвращается обратно.DarkMachine писал(а):Лажы нет - это же рекурсия, при каждом вызове та передаешь параметр через стек, а когда вызываешь процедуру ещё раз, то освобождение стека не происходит. Стек освобождается когда ты выходишь из процедуры, а это происходит (в твоем случае) если найденный элемент - это файл.Вообще в версии 10 сборщик мусора намного улучшен.
Все правильно, если найдена папка, то для нее снова рекурсивно вызывается эта-же процедура и так происходит, пока не будет достигнута последняя вложенная папка, после чего в ней сканируются файлы если они там есть или же процедура заканчивается если там ничего нет. Т.е. она заканчивается в любом случае и происходит откат вызовов. Проблема именно в строковых переменных. И проблема эта вообще с рекурсией никак не связана, просто при рекурсии она хорошо проявляется визуально. Для каждой динамической строки ANSI вызывается SysAllocStringByteLen, освобождается память SysFreeString, но вот происходит это не всегда. С юникодовыми строками такая же проблема.DarkMachine писал(а):Стек освобождается когда ты выходишь из процедуры, а это происходит (в твоем случае) если найденный элемент - это файл.
Не все. Динамические строки в стеке не размещаются, структуры да, динамические строки нет, в стеке размещается только указатель, в чем может убедится любой желающий. Стек здесь вообще не причем и рекурсия тоже. Тот-же алгоритм реализованный на VB к утечке памяти не приводит.jangle писал(а):В твоем коде при каждом вызове ScanDirectory в стеке размещаются все передаваемые параметры и локальные переменные.
ger_kar писал(а):тек здесь не причем, ибо указатель стека ESP возвращается обратно.
Может и в этом, но это опять же проблемы PB, ибо за это отвечает компилятор. И видимо его сделали крововато, потому что он с этим надлежащим образом не справляется.Хакер писал(а):Да вот число закоммиченных страниц не уменьшается. Может в этом дело?
ger_kar писал(а):Может и в этом, но это опять же проблемы PB
ger_kar писал(а):Тот-же алгоритм реализованный на VB к утечке памяти не приводит.
Почему, то же тогда тот же самый алгоритм, реализованный на нормально сделанном компиляторе VB работает корректно и не приводит ни к каким утечкам?Хакер писал(а):Нет, это вообще не проблема ни компилятора, ни чья либо ещё.
Причем здесь расход, когда речь идет именно об утечках. Расход это нормальное явление, а вот утечки нет. Расход это выделения памяти при необходимости, с последующим возвращением, когда такой необходимости более нет. Что собственно и демонстрирует тот-же самый алгоритм, реализованный на VB, когда в процессе сканирования идет расход памяти с последующим ее возвращением, когда сканирование окончено. В PB при каждом сканировании идет все новое и новое выделение памяти.jangle писал(а):Что-то в это слабо верится, подобный код будет приводит к расходу памяти на любом компиляторе.
Да собственно случайно, в процессе тестирования однотипного алгоритма параллельно в VB и PB. Что-бы была ощутимая разница решил просканить все файлы на всех дисках. Ну и почему-то решил посмотреть, кто при этом отъест у системы больше памяти PB или VB. После каждого из запусков память потребляемая VB возвращалась на круги своя, в то время как у PB она продолжала расти и расти и после 20 сканирований зашкалила за 50 Мб.Хакер писал(а):А как ты определил, что у тебя есть утечка?
...
DIM ss AS STRING
...
IF FindData.cFileName <> "." AND FindData.cFileName <> ".." THEN
ss = sFullName
ScanDirectory (ss)
END IF
DarkMachine писал(а):Не встаю за защиту языка, но этот алгоритм заезженный от и до. И если бы возникла утечка, то об этом давно уже знали.
В том то и дело, что алгорим такой, что в нем просто невозможно накосячить.DarkMachine писал(а):Не встаю за защиту языка, но этот алгоритм заезженный от и до.
DarkMachine писал(а):У меня самого есть исходник с рекурсией, причем от более тяжеловат и делает массу вещей, но утечки не происходит.
Ну попробуй еще раз или попробуй просканировать тем, что ты делал раньше большой объем и увидишь результат.jangle писал(а):Это точно, сам много раз использовал код для рекурсивного сканирования папок на PB, никогда проблем с утечками памяти не было.
ger_kar писал(а):Вообще экспериментировал с 10.02, вчера скачал 10.03, что касается юникодовых строк, то в 10.03 ситуация стала значительно лучше, но с обычными ANSI все осталось без изменений.
Вот то же самый алгоритм реализованный на VB, никаких утечек нет и в помине.
Нужно запустить тот и другой и сделать каждым по 10 сканированний, и как говорится - почувствуйте разницу.
Кстати я выяснил, что максимальная вложенность папок на диске C: у меня всего то ничего - 9 уровней, соответственно и рекурсия то всего ничего всего лишь 9 вложенных вызовов.
ScanDirectory
#COMPILE EXE "EnumFiles"
#REGISTER NONE
#DIM ALL
#INCLUDE "Win32Api.Inc"
DECLARE FUNCTION PathMatchSpec LIB "SHLWAPI.DLL" ALIAS "PathMatchSpecA"(pszFile AS ASCIIZ, pszSpec AS ASCIIZ) AS LONG
FUNCTION FileEnum(RootF AS WSTRING, File() AS WSTRING, Filter AS WSTRING) AS LONG
LOCAL FileName AS STRING, wFileName AS WSTRING, pFile, pFilter AS STRING
LOCAL Looper AS LONG
LOCAL FolderCount AS DWORD
STATIC FileCount AS DWORD
STATIC FolderDeep AS DWORD
DIM FileDD AS DIRDATA
pFilter = Filter
INCR FolderDeep
DIM SubFolder(0 TO 0) AS WSTRING
IF ASC(Rootf, - 1) <> 92 THEN Rootf = Rootf & "\"
SubFolder(0) = Rootf
FileName = DIR$(SubFolder(0) & "*", %SUBDIR OR %SYSTEM OR %HIDDEN OR %ReadOnly, TO FileDD ) 'Get folder or file
IF LEN(FileDD.FileName) THEN
DO
IF (GETATTR(SubFolder(0) & FileDD.FileName) AND %SUBDIR) THEN 'It's a subfolder
INCR FolderCount 'Keep track of how many subfolder
REDIM PRESERVE SubFolder(0 TO FolderCount)
SubFolder(FolderCount) = SubFolder(0) & FileDD.FileName & "\" '
ELSE 'GetAttr told us that it is a file
pFile = FileDD.FileName
IF PathMatchSpec(BYVAL STRPTR(pFile), BYVAL STRPTR(pFilter)) THEN 'Check against Filter
REDIM PRESERVE File(0 TO FileCount)
File(FileCount) = SubFolder(0) & FileDD.FileName
INCR FileCount
END IF
END IF
FileName = DIR$(NEXT, TO FileDD )
LOOP WHILE LEN(FileDD.FileName)
DIR$ CLOSE
FOR Looper = 1 TO FolderCount
FileEnum SubFolder(Looper), File() , Filter
NEXT
END IF
DECR FolderDeep
IF FolderDeep = 0 THEN
FUNCTION = FileCount
FileCount = 0 'Reset for subsequent call
END IF
END FUNCTION
FUNCTION PBMAIN()
DIM File(0 TO 0) AS WSTRING
LOCAL RootFolder AS WSTRING
LOCAL Filter AS WSTRING
LOCAL FileCount AS DWORD
RootFolder = "c:\"
Filter = "*.*"
FileCount = FileEnum(RootFolder, File(), Filter)
END FUNCTION
DarkMachine писал(а):а таск манагер его невидит.
После каждого запуска имеем постоянное приращение памяти.
А должны бы волновать. Потому что это не копейки, а потенциальная проблема, причем с моей точки зрения весьма серьезная. Меня например такие "мелочи" очень даже волнуют, потому, что маленькие утечки могут привести к большим проблемам.jangle писал(а):Меня это копейки что-то не особо волнуют, если расход и есть, то слишком незначительный.
После этого и я решил провести тест с целью выяснить потолок. Для теста выбрал тот же тест, что и выложенном последнем архиве, несколько его изменив и внедрив в него вечный цикл, приступил к тестированию. Запустил тест и ушел принимать завтрак.DarkMachine писал(а):Проверил. "Утечка" была -- точнее это не утечка, а использование памяти. Начал с 1200 кб закончил около 7600 кб.
Declare Function FindFirst Lib "kernel32.dll" Alias "FindFirstFileW" _
(ByVal lpFileName As WString, ByRef lpFindFileData As WIN32_FIND_DATAW) As Long
sTemp = swDirectory & "*"
hSearch = FindFirst(sTemp, DirInfo)
Но это не повод, чтобы отказываться от PB.
Так как передача параметра объявлена ByVal
может это показать на официальном форуме
Это надо проверить, вчера времени на это уже не было. И опять же надо проверить поведение как при вызовах WinApi, так и внутренние меж процедурные вызовы. Придется проверять, чтобы точно знать что к чему...Димитрий писал(а):Значит ли это, что все функции будут себя вести также?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 55