Найти - Пользователи
Полная версия: Помогите понять есть ли утечка памяти.
Начало » Python для экспертов » Помогите понять есть ли утечка памяти.
1 2
v3_62
Будьте добры помогите разобраться.
Имеет ли данный код утечку памяти?
При удаление класса должен выполняться __del__, но все они выполняются при закрытии основного окна.
В данном случае можно предположить что то остается в памяти после удалении класса.
Можно ли использовать данный метод если дополнительные окна создаются и удаляются много раз?

 # -*- coding: utf-8 -*-
import tkinter as tk
import gc
class win():
    num = 0
    def __init__(self, root, perent) -> None:
        self.root = root
        self.parent = perent
        win.num += 1
        self.tl = tk.Toplevel(self.root)
        # self.tl.geometry("600x400+100+100")
        self.tl.geometry("600x400")
        self.fr = tk.Frame(self.tl)
        self.fr.pack()
        self.lb = tk.Label(self.fr, text=str(win.num))
        self. lb.pack()
        self.bt = tk.Button(self.fr, text='Закрыть окно', command=self.exit1)
        self.bt.pack()
    def active(self):
        self.tl.mainloop()
    def exit1(self):
        # self.tl.destroy()
        self.parent.win_del()
    def __del__(self):
        print('__del__'*5)
class wroot():
    ltp = []
    def __init__(self):
        self.root = tk.Tk()
        self.root.geometry("800x600+10+10")
        self.fr = tk.Frame(self.root)
        self.fr.pack()
        self.bt = tk.Button(self.fr, text='Добавить окно', command=self.start)
        self.bt.pack()
        self.bt1 = tk.Button(self.fr, text='Удалить окно',
                             command=self.win_del)
        self.bt1.pack()
        self.root.mainloop()
    def start(self):
        wroot.ltp.append(win(self.root, self))
        wroot.ltp[-1].active()
    def win_del(self):
        if len(wroot.ltp) > 0:
            wroot.ltp[-1].bt.destroy()
            wroot.ltp[-1].fr.destroy()
            wroot.ltp[-1].tl.destroy()
            for obj in gc.get_referrers(wroot.ltp[-1]):
                print(':'*3, obj)
            print('\n')
            # mroot.ltp.pop()
            del wroot.ltp[-1]
            print(gc.garbage)
            print('\n')
if __name__ == '__main__':
    w = wroot()
PEHDOM
v3_62
При удаление класса должен выполняться __del__, но все они выполняются при закрытии основного окна.
нет не должен, __del__ вызывается когда счетчик ссылок на обьект становиться равен нулю.

https://pythonz.net/references/named/object.__del__/


v3_62
Получается что в __del__ нельзя писать код который должен выполняться при удаление объекта.
Если объект удален, то как можно посмотреть какие ссылки не него остались?
Если объект удален, то сборщик мусора должен поставить его в очередь на удаление,
если удалить не удается, то объект должен остаться в этой очереди до
удаления ссылок. Если я правильно понимаю gc.garbage должен показать
такие объект в списке, но список пустой.
В реальной задаче объекты могу создаваться и удаляться более
1000 раз и хочется быть уверенным, что данный подход годен для использования.
py.user.next
v3_62
Будьте добры помогите разобраться.
Прежде чем писать на Tkinter, почитай что-нибудь про Tkinter, рассмотри примеры программ. Не мешает ещё про Tcl/Tk почитать.
wiki. Tcl tck.tk. doc
wiki. Tk tkdocs. tutorial

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

v3_62
Если я правильно понимаю gc.garbage должен показать
такие объект в списке
Если тебе понадобился gc, значит ты что-то не то делаешь. Вряд ли он тебе понадобится, если ты будешь правильно код писать.
v3_62
Спасибо за советы и ответ.

 Если тебе понадобился gc, значит ты что-то не то делаешь. Вряд ли он тебе понадобится, если ты будешь правильно код писать.
Для того что бы правильно писать код надо понимать как работает python c tkinte, что я и хотел узнать.
В итоге так и не понял правильно работает код или нет. Единственный вывод использование __del__
с tkinter нежелательно.
py.user.next
v3_62
Для того что бы правильно писать код надо понимать как работает python c tkinte
Исходники питона, как и исходники Tkinter лежат в открытом доступе. Там можно всё прочитать, что и как там работает. Но ты их не поймёшь, потому что по твоему Великому Коду видно, что ты находишься на начальном уровне каком-то там.
https://github.com/python/cpython
https://github.com/python/cpython/blob/main/Modules/_tkinter.c

Так что не надо ничего выдумывать. Делай то, что делают все. Читай документацию, там куча примеров и все правильные. __del__ можно использовать, но я не думаю, что тебе и __del__ нужен. Мы просто время не тратим на вот эту вот фигню, которую ты себе придумал, а просто тебе сразу говорим, что тебе делать, чтобы, действительно, ты смог что-то написать.
PEHDOM
v3_62
Получается что в __del__ нельзя писать код который должен выполняться при удаление объекта.
ну вобщем да, по ссылке что давал написаны причины по которым счетчик может не дойти до нуля.
или вот еще с примерами и прочим: https://habr.com/ru/post/417215/

v3_62
Если объект удален, то как можно посмотреть какие ссылки не него остались?
ЕМНИП никак, у смого обьекта есть только счетчик ссылок, но он в общем не в курсе кто на него хранит ссылку.
v3_62
если объект удален, то сборщик мусора должен поставить его в очередь на удаление,
если удалить не удается, то объект должен остаться в этой очереди до
удаления ссылок.
нет del X просто уменьшает счетчик обьекта на 1, а уже сборщик проходя по обьектам смотрит на счетчик и решает удалять из памяти или нет. Там конечно еще алгоритмы поиска слабых и циклических ссылок, но вобщем и целом както так.
v3_62
Если я правильно понимаю gc.garbage должен показать
такие объект в списке, но список пустой.
у ткинтера под капотом твориться какоето колдунство, вот тут https://stackoverflow.com/questions/52839050/why-doesnt-tkinter-release-memory-when-an-instance-is-destroyed чутка поподробнее, но вобщем чтобы понять что там за магия нужно очень глубоко лезть в дебри ткинтера.



v3_62
py.user.next
Исходники питона, как и исходники Tkinter лежат в открытом доступе. Там можно всё прочитать, что и как там работает. Но ты их не поймёшь, потому что по твоему Великому Коду видно, что ты находишься на начальном уровне каком-то там.
;)))
Это точно не пойму, поэтому задал вопрос, тем кто понимает. А чем код не понравился? Он написан для примера, самый элементарный чтобы сразу было понятно в чем дело, выкладывать реальный код с кучей строк не относящегося к вопросу глупо.
py.user.next
Читай документацию, там куча примеров и все правильные.
В документации как правило элементарные примеры - пояснения. Единственный способ смотреть чужой код.

И все таки что не так с кодом?
Если так писать так нельзя, то где ошибка?
Если я не понимаю возможно кто то понимает и сможет ответить.


py.user.next
v3_62
А чем код не понравился? Он написан для примера, самый элементарный
Вот пример
v3_62
  
class win():
    num = 0
Оно должно быть записано вот так
  
class Win:
    num = 0
То есть ты синтаксис питона не знаешь даже. Имя класса должно быть записано с большой буквы и скобок там не должно быть, если класс ни от чего не наследуется явным образом.

На чем отражается то, что имя класса ты пишешь с маленькой буквы?
Вот фрагмент кода
v3_62
  
        self.root = root
        self.parent = perent
        win.num += 1
Сразу же возникает ряд вопросов к нему. Если win - это класс, то root справа от знака равно из первой строки - это класс или экземпляр класса? Если win - это класс, то perent справа от знака равно из первой строки - это класс или экземпляр класса? Если win - это класс, то self слева от знака равно из первой строки - это класс или экземпляр класса?
И на эти вопросы надо сидеть и искать ответы, вместо того чтобы понять сразу всё просто по тому, как это записано.

Когда же всё по правилам сделано
  
class Win:
    num = 0
 
win = Win()
win1 = win
Мы видим, что win - это экземпляр класса, а Win - это класс. Причём там, где скобок не должно быть, их нет, а где они должны быть, они есть. И мы видим, что win справа от знака равно в последней строке является экземпляром класса и win1 слева от знака равно в последней строке является экземпляром класса. То есть мы сразу видим, где класс, а где не класс. Нам не нужно сидеть и думать над этим, тратя время на понимание каждой строчки.

И тут же участок кода, который гипотетически появляется впоследствии
  
win.num += 1
Win.num += 1
Он является информативным. Мы видим, что сначала в экземпляре класса win инкрементируется что-то, а потом в классе Win инкрементируется что-то. Нам не надо до этого додумываться, тут видно всё по первым буквам в их названиях.

v3_62
выкладывать реальный код с кучей строк не относящегося к вопросу глупо
Из-за того, что ты так пишешь безграмотно, никто не станет читать твой код с кучей строк. Зачем тратить время на расшифровку безграмотного кода? вряд ли в безграмотном коде будет что-то умное в алгоритмическом плане. Очень велика вероятность того, что автор безграмотного кода строит и алгоритмы безграмотно. Придётся ещё алгоритмы разгребать.

Также в этом коде
v3_62
  
        if len(wroot.ltp) > 0:
            wroot.ltp[-1].bt.destroy()
            wroot.ltp[-1].fr.destroy()
            wroot.ltp[-1].tl.destroy()
Видно, что ты занимаешься ерундой, потому что не понимаешь даже, для чего элементы прикрепляются друг к другу при их создании. Дочерние элементы прикрепляются к родительским.

Вот тут, в документации, про которую я тебе писал выше, которую ты не читал вообще, ибо долго, неинтересно и так далее
https://tcl.tk/man/tcl8.6/TkCmd/destroy.htm
сказано, что destroy() действует на всё дерево, прикреплёных друг к другу элементов. Для этого они и прикрепляются друг к другу, а не просто так от нечего делать кто-то придумал это зачем-то.

То есть
  
wroot.ltp[-1].destroy()
хватило бы, чтобы выполнить это всё, что ты там понаписал. Но это надо знать. А чтобы это знать, это надо прочитать.

В итоге: не зная элементарнейших вещей, ты предлагаешь тратить время нам на то, чтобы разжёвывать тебе всякие такие вещи, которые давно и в полной мере разжёваны во всех книжках от “для самых маленьких” до “для профессионалов”.

Да, и ещё такой вопрос. Как так получилось, что ты, всё типа зная сам, не смог определить, есть ли утечка памяти в твоём коде? Ведь код элементарный, как ты говоришь. Да и читать ничего не надо, ведь всё можно понять просто так, сходу. Вот подумай просто. Как ты наваял код, который не можешь проанализировать. То есть ты не умеешь писать коды, понятные даже для самого себя?
xam1816
v3_62
Имеет ли данный код утечку памяти?
Может взять какой-нибудь инструмент для тестирования,который бы показал количество памяти с окнами и без окон по факту, на подобии memory profiler?
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB