purebasic.info

PureBasic forum
Текущее время: Пт авг 23, 2019 12:48 pm

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 46 ]  На страницу 1, 2, 3, 4  След.
Автор Сообщение
 Заголовок сообщения: Утечка памяти
СообщениеДобавлено: Пт апр 19, 2019 10:51 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Не нашел подходящего раздела - пишу сюда.

Ситуация.
Сделал утилиту которая в цикле опрашивает сеть и рисует график.
Запустил. Работает как и задумано.
Но быстро растет занятая память хотя по задумке такого быть не должно.
Тщательно просмотрел код - нашел косяк, исправил.
Быстрый рост выделенной памяти исчез.
Но медленный - скачками по несколько кб за десяток секунд - остался.
Визуально - скачки не привязаны к циклам опроса.
Нашел такую утилиту HeapMemView.exe для просмотра выделенных блоков памяти.
Думал - увижу постепенный рост количества выделенных блоков памяти.
И не увидел. Количество блоков колебалось около 440-450 шт.
Что согласуется с алгоритмом программы - периодически требуются блоки для обработки полученных данных и затем эти блоки освобождаются.
А выделенная память помаленьку увеличивается.
Но это не за счет забытых блоков памяти.

Вопрос.
За счет чего? Где еще можно порыться?

P.S. Заметил интересную вещь.
Среди списка блоков памяти выделенных системой программе есть несколько выделяющихся своим размером - 256000 байт.
И их количество равно количеству запущенных потоков.
Думаю что это область стека для каждого потока.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пт апр 19, 2019 11:34 am 
Не в сети
профессор

Зарегистрирован: Чт фев 09, 2017 10:37 am
Сообщений: 492
Благодарил (а): 34 раз.
Поблагодарили: 56 раз.
Пункты репутации: 0
Я бы попробовал разделить код на части и запускать каждые части отдельно и смотреть какая создаёт утечку. Или обратным исключением, типа заглушки вставить и тестировать.

Может проверить для каких функций нужно освобождение и выполняются ли они, нет ли выпрыгов из процедуры до того как будут освобождены ресурсы.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пт апр 19, 2019 12:22 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11505
Благодарил (а): 4 раз.
Поблагодарили: 469 раз.
sadstar писал(а):
в цикле опрашивает сеть и рисует график.
Соединения с сетью закрываются?
Запустите диспетчер задач и откройте окно в меню Вид -> Выбрать столбцы.
В нем поставьте галочки во всех пунктах начинающихся с Память, а также в Дескрипторы, Счетчик потоков, Объекты USER и Объекты GUI.
Посмотрите какой из этих параметров будет увеличиваться.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пт апр 19, 2019 3:53 pm 
Не в сети
профессор

Зарегистрирован: Пт фев 20, 2009 12:57 pm
Сообщений: 1766
Откуда: Алматы
Благодарил (а): 17 раз.
Поблагодарили: 49 раз.
Пункты репутации: 5
рисуется в канвас или в изображение? рисуется в одно и то-же изображение или создается новое с тем-же именем? если создается новое с тем-же именем - то освобождается ли перед этим старое?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Сб апр 20, 2019 7:37 am 
Не в сети
профессор

Зарегистрирован: Вт май 13, 2014 4:12 am
Сообщений: 864
Благодарил (а): 90 раз.
Поблагодарили: 26 раз.
Пункты репутации: 5
тоже про картинки подумал
картинки нужно удалять сразу и обязательно через проверку
Код:
1
If IsImage(img):FreeImage(img):EndIf


если в функции есть локальная картинка, её надо обязательно удалять, дело в том что при завершении функции удалятся только переменные, а сама картинка останется, удалится переменная где была "ссылка" на картинку и картинка навечно останется в памяти
и как сказал AZJIO проверять перед ProcedureReturn наличие картинок
всё это совсем не очевидно, но оно есть, сам с этим сталкивался


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пн апр 22, 2019 3:43 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
Пётр писал(а):
sadstar писал(а):
в цикле опрашивает сеть и рисует график.
Соединения с сетью закрываются?
Запустите диспетчер задач и откройте окно в меню Вид -> Выбрать столбцы.
В нем поставьте галочки во всех пунктах начинающихся с Память, а также в Дескрипторы, Счетчик потоков, Объекты USER и Объекты GUI.
Посмотрите какой из этих параметров будет увеличиваться.


Есть подозрение на параметр Дескрипторы.
При работе 12-ти потоков в цикле число дескрипторов меняется туда-сюда от ~160 до ~180 со смещением диапазона колебаний вверх .
При останове(закрытии) потоков по истечению ~10 мин работы остается дескрипторов ~90.
Несколько последовательных циклов "Старт / ~10 мин работы / Стоп потоки" показывают число оставшихся дескрипторов 92, 94, 96, 98.

Что Описывают эти дескрипторы?
Открытых файлов нет.
Видимых Гаджетов в окне 12*3+9=45 + ScrollArea + StatusBar(1item) + стандартные кнопки окна (3).
+ 12 Images

Куда рыть дальше?


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пн апр 22, 2019 5:18 am 
Не в сети
профессор

Зарегистрирован: Сб фев 06, 2016 6:18 pm
Сообщений: 311
Благодарил (а): 14 раз.
Поблагодарили: 38 раз.
Пункты репутации: 2
sadstar писал(а):
Что Описывают эти дескрипторы?
Может и сокеты. Хорошо бы для каждого socket сделать CloseNetworkConnection, что бы он не сидел в CLOSE_WAIT.
При завершении потока, все гаджеты созданные в нем нужно освободить с помощью FreeGadget :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Пн апр 22, 2019 7:57 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
в функции работы с сетью на каждый
Connection = OpenNetworkConnection(IP$, 161 , #PB_Network_UDP)
есть свой
CloseNetworkConnection(Connection)


В потоках гаджеты не создаются.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Вт апр 23, 2019 4:01 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
https://yadi.sk/d/x1LpfIweo1Ixqw

у кого есть в сети управляемые свичи - можно попробовать мою "игрушку"

всего ~136 кБ


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Вт апр 23, 2019 10:33 am 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11505
Благодарил (а): 4 раз.
Поблагодарили: 469 раз.
По исполняемому файлу не так просто определить из-за чего происходит утечка памяти. Можно лишь зафиксировать факт и приблизительно установить причину.

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Вт апр 23, 2019 2:51 pm 
В сети
профессор

Зарегистрирован: Чт сен 22, 2011 6:21 pm
Сообщений: 286
Благодарил (а): 40 раз.
Поблагодарили: 28 раз.
Пункты репутации: 0
1) Наиболее вероятна утечка в потоках, смотрим внимательно их, чистить надо все кроме простых переменных(массивы, списки, карты, соединения, итд)
2) Если не справляетесь выложите на обозрение хотя-бы поточные процедуры.
3) Если "совсем секретно", но надо что-бы работало долго и не сьело всю память, то в качестве черезжопного метода - самоперезапуск.


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Ср апр 24, 2019 9:34 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
https://yadi.sk/d/x1LpfIweo1Ixqw

там же папка sources

Буду рад если кто нибудь поюзает плоды моих мыслительных усилий.
Если это не очередное "изобретение велосипеда".


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Ср апр 24, 2019 10:34 am 
В сети
профессор

Зарегистрирован: Чт сен 22, 2011 6:21 pm
Сообщений: 286
Благодарил (а): 40 раз.
Поблагодарили: 28 раз.
Пункты репутации: 0
Надеюсь вы не будете обижаться на конструктивную критику, навскидку:
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Procedure.l BERenc_OID(OID$) ; возвращает указатель на начало блока памяти содержащего результат
        Protected *mem, memLen, np, value, *buf, bufLen, i
        If Left(OID$,1)="." ;удалить начальную точку
                OID$=Mid(OID$,2)
        EndIf
        np=CountString(OID$,".") ; колич. точек в OID$
        If np<1
                ProcedureReturn #False
        EndIf
        ; первые два subidentifier кодируются отдельно
        ;value=Val(StringField(OID$,1,".")) *40 + Val(StringField(OID$,2,"."))
        *buf=BERenc_Value(Val(StringField(OID$,1,".")) *40 + Val(StringField(OID$,2,".")))
        If Not *buf: ProcedureReturn #False: EndIf
        bufLen=MemorySize(*buf)
        *mem=AllocateMemory(bufLen)
        If Not *mem: ProcedureReturn #False: EndIf
        CopyMemory(*buf, *mem, bufLen)
        FreeMemory(*buf)
        ;остальные subidentifiers
        If np > 1 ; есть как минимум третье поле
                For i=3 To np+1
                        *buf=BERenc_Value(Val(StringField(OID$,i,".")))
                        If Not *buf: ProcedureReturn #False: EndIf
                        bufLen=MemorySize(*buf)
                        memLen=MemorySize(*mem)
                        *mem=ReAllocateMemory(*mem, memLen+bufLen) ;увеличить блок памяти
                        If Not *mem: ProcedureReturn #False: EndIf
                        CopyMemory(*buf, *mem+memLen, bufLen)
                        FreeMemory(*buf)
                Next
        EndIf
        ;дооформить блок
        memLen=MemorySize(*mem)
        *buf=BERenc_Value(memLen) ; кодировка длины - может быть многобайтной
        bufLen=MemorySize(*buf)
        *mem=ReAllocateMemory(*mem, memLen+bufLen+1) ;увеличить блок памяти
        MoveMemory(*mem, *mem+bufLen+1, memLen) ; освободить 2 первых байта
        PokeB(*mem,$06) ; тип данных = OID
        CopyMemory(*buf, *mem+1, bufLen) ; длина данных
        FreeMemory(*buf)
        ProcedureReturn *mem
EndProcedure
 


Итак:
1) Строка 12: выделяем память (внутри BERenc_Value) и указатель у нас в *buf (пока все нормально)
2) Строка 15: выделяем память, указатель в *mem
3) Строка 16: "If Not *mem: ProcedureReturn #False: EndIf" ??? вот так просто выходим, не очистив память в *buf ???
4) Строка 22: Снова выделяем память в тот-же указатель, не очистив предыдущую ??? (нет сама не очистится)
5) Строка 27: И снова выходим забив на *buf
6) Строка 34: И снова выделяем не освободив...


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Ср апр 24, 2019 12:48 pm 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11505
Благодарил (а): 4 раз.
Поблагодарили: 469 раз.
В чем смысл этой процедуры из SNMP_requester_1.pbi?
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Procedure crashFreeMemory()
        ;DisableExplicit
 
        Shared *mem, MemSize, *buf, BufSize, DataSize, *len, lenSize, p
        Shared *Community, Community_Size, *Ver, Ver_Size
        Shared *RequestID, RequestID_Size, *Error_Stat, Error_Stat_Size
        Shared *Error_Idx, Error_Idx_Size, *OID, OID_Size, *Null, Null_Size
        Shared *VarBandList, VarBandListSize, *PDU, PDU_Size
        If *mem : FreeMemory(*mem): EndIf
        If *buf : FreeMemory(*buf): EndIf
        If *len : FreeMemory(*len): EndIf
        If *Community : FreeMemory(*Community): EndIf
        If *Ver : FreeMemory(*Ver): EndIf
        If *RequestID : FreeMemory(*RequestID): EndIf
        If *Error_Stat : FreeMemory(*Error_Stat): EndIf
        If *Error_Idx : FreeMemory(*Error_Idx): EndIf
        If *OID : FreeMemory(*OID): EndIf
        If *Null : FreeMemory(*Null): EndIf
        If *VarBandList : FreeMemory(*VarBandList): EndIf
        If *PDU : FreeMemory(*PDU): EndIf
       
        ;EnableExplicit
 
EndProcedure

В программе нет этих глобальных указателей и она память не освободит. С учетом ее вызова из кода, правильнее было использовать макрос.
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Macro crashFreeMemory()
        ;DisableExplicit
 
        If *mem : FreeMemory(*mem): EndIf
        If *buf : FreeMemory(*buf): EndIf
        If *len : FreeMemory(*len): EndIf
        If *Community : FreeMemory(*Community): EndIf
        If *Ver : FreeMemory(*Ver): EndIf
        If *RequestID : FreeMemory(*RequestID): EndIf
        If *Error_Stat : FreeMemory(*Error_Stat): EndIf
        If *Error_Idx : FreeMemory(*Error_Idx): EndIf
        If *OID : FreeMemory(*OID): EndIf
        If *Null : FreeMemory(*Null): EndIf
        If *VarBandList : FreeMemory(*VarBandList): EndIf
        If *PDU : FreeMemory(*PDU): EndIf
       
        ;EnableExplicit
 
EndMacro

В этой процедуре можно получить "реальный облом"
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Procedure SaveFailedBlock(*Response, Ref$)
        Static FixPart$="", Counter=0
        LockMutex(mtx_LogFailedBlock)
        If Len(FixPart$)=0
                FixPart$=FormatDate("%yyyy%mm%dd%hh%ii%ss", Date())
        EndIf
        Counter+1
        Protected LogFile$=GetPathPart(ProgramFilename())+"FailedBlock-"+FixPart$+RSet(Str(Counter),8,"0")+".txt"
        Protected nFile=CreateFile(#PB_Any, LogFile$, #PB_File_NoBuffering)
        If Not nFile
                MessageRequester("", "Облом при создании файла <"+LogFile$+">")
                ProcedureReturn #False 
        EndIf
       
        Protected Block$=MemoryToHex(*Response, MemorySize(*Response), ".")
       
        WriteStringN(nFile, Ref$)
        WriteStringN(nFile, "MemorySize(*Response)="+Str(MemorySize(*Response)))
        WriteStringN(nFile, Block$)
 
        CloseFile(nFile)
       
        UnlockMutex(mtx_LogFailedBlock)
       
EndProcedure

если будет выполнено условие в коде
Код:
1
2
3
4
        If Not nFile
                MessageRequester("", "Облом при создании файла <"+LogFile$+">")
                ProcedureReturn #False 
        EndIf

мьютекс не освобождается и дальнейший это захват может привести к блокировке потока.

В процедуре MakeRequestBlock в строке 236 выделяется память. Где она освобождается?

В этом участке кода (процедура GetSNMPresponse) соединение не будет закрыто при выполнении условия If Pack_Size>2048
Код:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        ; создать соединение (для UDP - псевдосоединение)
        Connection = OpenNetworkConnection(IP$, 161 , #PB_Network_UDP)
        If Not Connection
                *Error\l=802
                FreeMemory(*DataBuffer)
                ProcedureReturn #False
        EndIf
        Pack_Size=MemorySize(*Pack)
        ;On UDP connections, the maximum 'Length' is 2048. On TCP connections, the maximum 'Length' is 65536.
        If Pack_Size>2048
                *Error\l=803
                FreeMemory(*DataBuffer)
                ProcedureReturn #False
        EndIf

В этой же процедуре в строке 426 выделяется память
Код:
1
Protected NewAddrOfResponseBlock=AllocateMemory(Result) ;запросить блок под принятые данные

Где она освобождается?

_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения: Re: Утечка памяти
СообщениеДобавлено: Чт апр 25, 2019 2:27 am 
Не в сети
ассистент

Зарегистрирован: Вт мар 06, 2018 7:45 am
Сообщений: 16
Благодарил (а): 0 раз.
Поблагодарили: 0 раз.
Пункты репутации: 0
>В процедуре MakeRequestBlock в строке 236 выделяется память. Где она освобождается?
запоминается в массив
Код:
1
242 aAddrOfSEQ(i-1)=*seq


зачищается при ошибке
Код:
1
2
3
4
262 If aAddrOfSEQ(i-1)
263  *mem=aAddrOfSEQ(i-1)
264   FreeMemory(*mem)
265 EndIf



зачищается при нормальной работе
Код:
1
2
3
4
5
6
7
295 For i=1 To QTY_OID
 *mem=aAddrOfSEQ(i-1)
  len_mem=MemorySize(*mem)
  CopyMemory(*mem,*VarBandList+p,len_mem)
  p+len_mem
300  FreeMemory(*mem) ;=============================
301 Next i



вот как раз в строке 300 была добавка после обнаружения большой утечки памяти


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 46 ]  На страницу 1, 2, 3, 4  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB