Kivy RecycleView генерирует все больше и больше объектов, которые не собираются сборщиком мусора.Python

Программы на Python
Ответить
Anonymous
 Kivy RecycleView генерирует все больше и больше объектов, которые не собираются сборщиком мусора.

Сообщение Anonymous »

Я использовал пример с https://github.com/kivy/kivy/blob/maste ... ic_data.py и изменил его только для предоставления некоторой статистики сборщика мусора. Я вижу, что объекты генерируются каждый раз, когда выполняется операция RecycleView - заполнение, очистка, прокрутка и т. д. Эти объекты не исчезают со временем - общее количество продолжает расти.
Кто-нибудь знает, что может быть причиной этого, конечно, это вряд ли ошибка в самом RecycleView - это должно было быть давно обнаружено. Возможно, в примере есть проблема или конкретная комбинация версий ПО. Моя настройка такова:
Windows 10 Pro 20H2 64-разрядная версия, Python 3.12.4 32-разрядная версия (необходимо вызывать 32-разрядные устаревшие библиотеки .NET)
Kivy v2.3.0.
Пример статистики, которую я вижу с помощью всего лишь нескольких операций заполнения/очистки и действий прокрутки колесика мыши с нажатием кнопки «Отчет» между:
Изображение

Количество объектов многих различных типов увеличивается, но классы "traceback", "frame" и "function" являются самыми многочисленными:
Изображение

Это код:

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

from random import sample, randint
from string import ascii_lowercase

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
import gc
import json
from colorama import init, deinit, Fore, Style

def cprint(*args, red=False, newline=True):
init(autoreset=True) # colorama
text = '    '
for arg in args:
text+= (str(arg) + ' ')
if newline:
print(Style.BRIGHT + (Fore.RED if red else Fore.YELLOW) + text + Fore.RESET)
else:
print(Style.BRIGHT + (Fore.RED if red else Fore.YELLOW) + text + Fore.RESET, end='')
deinit() # colorama deinit

kv = """
:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
id: name
Label:
text: root.value

:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
Button:
text: 'Remove first item'
on_press: root.remove()
Button:
text: 'Report'
on_press: root.check_garbage()

RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
"""

Builder.load_string(kv)

class Test(BoxLayout):

def populate(self):
self.rv.data = [
{'name.text': ''.join(sample(ascii_lowercase, 6)),
'value': str(randint(0, 2000))}
for x in range(50)]

def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['name.text'])

def clear(self):
self.rv.data = []

def insert(self, value):
self.rv.data.insert(0, {
'name.text': value or 'default value', 'value':  'unknown'})

def update(self, value):
if self.rv.data:
self.rv.data[0]['name.text'] = value or 'default new value'
self.rv.refresh_from_data()

def remove(self):
if self.rv.data:
self.rv.data.pop(0)

def check_garbage(self):
'''
store garbage types in json file to avoid creating new objects each time this runs
'''

if not hasattr(self, 'softwarerestarted'):
self.softwarerestarted = True

''' record all objects stats '''
gc.collect()
gc_objectsnow = gc.get_objects()
uncollectable_garbage = len(gc.garbage)
garbagetypes = {}
for obj in gc_objectsnow:
''' record numbers by type '''
if not str(type(obj)) in garbagetypes:
garbagetypes[str(type(obj))] = 1
else:
garbagetypes[str(type(obj))] +=1

if self.softwarerestarted:
garbagetypesrecord=[garbagetypes]
self.softwarerestarted = False
else:
with open('C:/Temp/garbagerecord.json') as file:
garbagetypesrecord = json.load(file)
garbagetypesrecord.append(garbagetypes)
with open('C:/Temp/garbagerecord.json', 'w') as file:
json.dump(garbagetypesrecord, file)

''' now report results '''
for index, record in enumerate(garbagetypesrecord):
printrows = []
firstprintrow = []
firstprintrow.append("--- Garbage report " + str(index+1) + ":")
printrows2 = []
totalcount, totalprevcount = 0, 0
for key, value in record.items():
totalcount+=value
if index > 0:
totalprevcount+=garbagetypesrecord[index-1].get(key,0)
diff = value - garbagetypesrecord[index-1].get(key,0)
if diff > 0:
#if diff < 100 and diff > 0:
printrow =[]
printrow.append('    ' + str(key))
printrow.append(str(value))
printrow.append(("+" + str(diff)) if diff >= 0 else str(diff))
printrows2.append(printrow)
diff = totalcount - totalprevcount
firstprintrow.append("all objects " + str(totalcount))
if index > 0: firstprintrow.append((" +" + str(diff)) if diff >= 0 else str(diff))
firstprintrow.append(" of which uncollectable " + str(uncollectable_garbage))
printrows.append(firstprintrow)
if index == len(garbagetypesrecord)-1: printrows+=printrows2
for row in printrows:
for word in row:
cprint(word, red = True if ('+' in word and not '+0' in word) else False, newline=False)
cprint('')
print('')

class TestApp(App):
def build(self):
return Test()

if __name__ == '__main__':
TestApp().run()
----РЕДАКТИРОВАНИЕ----
Только что воспроизведено в другой системе с 64-битной версией Python:
Windows 10 Pro 22H2
[INFO ] [Kivy ] v2.3.1
[INFO ] [Python ] v3.8.10 (tags/v3.8.10:3d8993a, 3 мая 2021 г., 11:48:03) [MSC v.1928 64 бит (AMD64)]
Количество объектов продолжает расти, даже если я просто прокручиваю вверх и вниз представление таблицы, не меняя ее содержимого.
----РЕДАКТИРОВАНИЕ 2----
I использовал следующую функцию, взятую с https://github.com/kivy/kivy/issues/5718

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

def memcheck():
# return the memory usage in MB
process = psutil.Process()
mem = process.memory_info().rss / float(2 ** 20)
mem = str(mem) + "MB"
return mem
Чтобы добавить фактическое использование памяти в статистику. Я тоже попробовал это сделать, просто чтобы исключить возможность того, что проблема в моем собственном методе check_garbage(). Однако та же история: использование памяти продолжает расти с каждой новой прокруткой вверх/вниз.

Подробнее здесь: https://stackoverflow.com/questions/798 ... d-by-garba
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»