Помогите разобраться, что кушает память

Рейтинг: 1Ответов: 1Опубликовано: 28.02.2025

Есть простой тг бот, который АФК ждет, когда ему отправят таблицу Эксель. Как только получает, он е обрабатывает и возвращает. Бот лежит на сервере арендованном в облаке. На сервере 2 гига оперативки, при этом в пассивном состоянии бот кушает 10% памяти, а в активном 12. На мой взгляд для бота, который ничего не делает это слишком. Добавил в него pympler, вот что получил

Использование памяти:
                                                  types |   # objects |   total size
======================================================= | =========== | ============
                                                   dict |      164203 |     37.97 MB
                                                    str |       67892 |     11.68 MB
                                                   code |       22421 |      3.88 MB
                                                   type |        2906 |      2.49 MB
                                                  tuple |       28081 |      1.80 MB
                                                   list |       12489 |    990.35 KB
                                                    set |        1896 |    877.44 KB
                                  weakref.ReferenceType |        7509 |    527.98 KB
                                              frozenset |        1348 |    514.09 KB
                  openpyxl.descriptors.MetaSerialisable |         424 |    444.12 KB
                              pydantic.fields.FieldInfo |        1989 |    435.09 KB
  pydantic._internal._model_construction.ModelMetaclass |         410 |    429.22 KB
                             builtin_function_or_method |        4541 |    319.29 KB
                                            abc.ABCMeta |         287 |    296.72 KB
           pydantic_core._pydantic_core.SchemaValidator |         408 |    248.62 KB

ни о каких 200мб тут вообще речи не идёт. введите сюда описание изображения Вопрос - куда расходуется память? как понять и как пофиксить?

введите сюда описание изображения

import asyncio
import logging
import os
from aiogram import Bot, types, Dispatcher, F
from aiogram.enums import ParseMode
from aiogram.filters import Command
from aiogram.types import BotCommand, InputFile
from aiogram.types import FSInputFile
from aiogram.client.default import DefaultBotProperties
import rocv
import GSV_CHSV
from rocv import rocv_first, rocv_second
from nv_ssch import nv
from TV_sebes import tv_seb
from ingridientmap import ingridient
from invent import invent
from aiogram.fsm.context import FSMContext

import BotFraz
from pympler import summary, muppy, asizeof

ADMIN_ID = 506522036

logger = logging.getLogger(__name__)
TOKEN = ""

bots = Bot(TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
dp = Dispatcher()


async def comm(bot: Bot):
    command = [
        BotCommand(
            command='start',
            description='Начало работы бота'
        ),
        BotCommand(
            command='help',
            description='Помощь'
        )
    ]
    await bot.set_my_commands(command)


@dp.message(F.document)
async def handle_document(message: types.Message, bot: Bot, state: FSMContext):
    file = message.document.file_name
    try:
        match file:
            case 'НВ_ССЧ.xlsx':
                doc = await nv(message, bot)
                await result(message, doc)
                os.remove(doc)
            case 'ТВ_себестоимость.xlsx':
                doc = await tv_seb(message, bot)
                await result(message, doc)
                os.remove(doc)
            case 'Карта_ингредиентов.xlsx':
                doc = await ingridient(message, bot)
                await result(message, doc)
                os.remove(doc)
            case 'Инвентаризация.xlsx':
                doc = await invent(message, bot)
                await result(message, doc)
                os.remove(doc)
            case 'росв.xlsx':
                await rocv_first(message, bot, state)
            case 'росв1.xlsx':
                doc = await rocv_second(message, bot, state)
                await result(message, doc)
                os.remove(doc)
            case 'гсв.xlsx':
                await GSV_CHSV.gsv(message, bot, state)
            case 'чсв.xlsx':
                doc = await GSV_CHSV.chsv(message, bot, state)
                await result(message, doc)
                os.remove(doc)
            case _:
                await message.answer('А я не знаю что делать с этим файлом... '
                                     'Назови его как то по другому. '
                                     'Что бы узнать как можешь нажать помощь в меню')
        all_objects = muppy.get_objects()
        summ = summary.summarize(all_objects)
        summary_text = "Использование памяти:\n"
        for line in summary.format_(summ):
            summary_text += line + "\n"
        await bot.send_message(506522036,summary_text)

        dict_objects = [obj for obj in all_objects if isinstance(obj, dict)]
        with open("example.txt", "w", encoding="utf-8") as file:
            file.write (f"Найдено словарей: {len(dict_objects)} \n")
        with open("example.txt", "w", encoding="utf-8") as file:
            for i, dict_obj in enumerate(dict_objects):  # Покажем первые 10 словарей

                file.write (f"Словарь {i + 1}:\n")
                file.write (f"  Ключи: {list(dict_obj.keys())[:5]}...\n")  # Покажем первые 5 ключей
                file.write (f"  Значения: {list(dict_obj.values())[:5]}...\n")  # Покажем первые 5 значений
                file.write (f"  Размер: {dict_obj.__sizeof__() / 1024:.2f} KB\n")
                file.write(f"--------------------------------------------------------\n\n")

        await bot.send_document(506522036,document="example.txt")


    except:
        await message.answer('Что то пошло не так ((((')


async def result(message: types.Message, doc):
    out = FSInputFile(str(doc))
    await message.answer_document(out)
    await message.answer(await BotFraz.ask(f"это было очень просто для тебя"))


async def start_up(bot: Bot):
    await comm(bot)
    await bot.send_message(ADMIN_ID, text='Бот запущен')


@dp.message(Command(commands=['start']))
async def on_start(message: types.Message):
    await message.answer('Здравствуйте! Я ваш иногда дружелюбный помощник. Я умею работать с разными табличками.'
                         ' Всё что вам нужно сделать, это отправить мне табличку с правильным названием. '
                         'Что бы узнать, как должен называться файл, отправьте мне команду /help'
                         ' или выберете её в меню. Если вдруг у вас есть идеи о том, какую ещё '
                         'табличку научить меня обрабатывать, сообщите об этом Илье и'
                         ' он подумает над вашим предложением. ')


@dp.message(Command(commands=['help']))
async def on_start1(message: types.Message):
    await message.answer('Я знаю что делать с файлами у которых такое название')
    await message.answer('НВ_ССЧ.xlsx')
    await message.answer('ТВ_себестоимость.xlsx')
    await message.answer('Карта_ингредиентов.xlsx')
    await message.answer('Инвентаризация.xlsx')
    await message.answer('росв.xlsx')
    await message.answer('росв1.xlsx')


async def starter():
    logging.basicConfig(
        level=logging.INFO
    )
    dp.include_routers(rocv.router,GSV_CHSV.router)
    dp.startup.register(start_up)
    # dp.shutdown.register(shutdown)
    await bots.delete_webhook(drop_pending_updates=True)
    await dp.start_polling(bots, skip_updates=True)


if __name__ == "__main__":
    asyncio.run(starter())

Такое ощущение, что проблема с asyncio, потому что даже код ниже создал Всего объектов в памяти: 325882 Словарей найдено: 137083

import asyncio

from aiogram import Bot, Dispatcher
import inspect

from pympler import summary, muppy, asizeof

ADMIN_ID = ---

TOKEN = " "

bots = Bot(TOKEN)
dp = Dispatcher()

async def logg():
    all_objects = muppy.get_objects()
    summ = summary.summarize(all_objects)
    summary_text = "Использование памяти:\n"
    for line in summary.format_(summ):
        summary_text += line + "\n"
    print(summary_text)

    dict_objects = [obj for obj in all_objects if isinstance(obj, dict)]

    with open("example.txt", "w", encoding="utf-8") as file:
        file.write(f"Найдено словарей: {len(dict_objects)} \n")

        # Ограничим количество выводимых словарей
        max_dicts_to_show = 50
        for i, dict_obj in enumerate(dict_objects[:max_dicts_to_show]):
            # Логируем информацию о создании словарей
            file.write(f"Словарь {i + 1}:\n")
            file.write(f"  Ключи: {list(dict_obj.keys())[:5]}...\n")
            file.write(f"  Значения: {list(dict_obj.values())[:5]}...\n")
            file.write(f"  Размер: {dict_obj.__sizeof__() / 1024:.2f} KB\n")

            # Попробуем добавить контекст создания словаря (стек вызовов)
            stack_trace = inspect.stack()[:3]  # Логируем только последние 3 вызова
            for frame in stack_trace:
                file.write(f"  Файл: {frame.filename}, строка {frame.lineno}, функция {frame.function}\n")

            file.write(f"--------------------------------------------------------\n\n")
    print(f"Всего объектов в памяти: {len(all_objects)}")
    print(f"Словарей найдено: {len(dict_objects)}")
    print(f"--------------------------------------------------------\n\n")
async def starter():


    await bots.delete_webhook(drop_pending_updates=True)
    await logg()
    await dp.start_polling(bots, skip_updates=True)

if __name__ == "__main__":
    asyncio.run(starter())


Найдено словарей: 137083 
Словарь 1:
  Ключи: []...
  Значения: []...
  Размер: 0.05 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 2:
  Ключи: []...
  Значения: []...
  Размер: 0.05 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 3:
  Ключи: ['PY_START', 'PY_RESUME', 'PY_RETURN', 'PY_YIELD', 'CALL']...
  Значения: [1, 2, 4, 8, 16]...
  Размер: 0.44 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 4:
  Ключи: ['__doc__', '__module__']...
  Значения: ['Thread-local dummy', '_thread']...
  Размер: 0.16 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 5:
  Ключи: []...
  Значения: []...
  Размер: 0.05 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 6:
  Ключи: ['ALLUSERSPROFILE', 'APPDATA', 'CommonProgramFiles', 'CommonProgramFiles(x86)', 'CommonProgramW6432']...
  Значения: ['C:\\ProgramData', 'C:\\Users\\Смолев\\AppData\\Roaming', 'C:\\Program Files\\Common Files', 'C:\\Program Files (x86)\\Common Files', 'C:\\Program Files\\Common Files']...
  Размер: 1.53 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run
--------------------------------------------------------

Словарь 7:
  Ключи: []...
  Значения: []...
  Размер: 0.05 KB
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 38, функция logg
  Файл: C:\Users\Смолев\PycharmProjects\buhhelp\main.py, строка 50, функция starter
  Файл: C:\Users\Смолев\AppData\Local\Programs\Python\Python313\Lib\asyncio\events.py, строка 89, функция _run

Ответы

▲ -1

Сильно не ругайся я не программист, а так себе, возможно дело в структурах данных? К примеру list и tuple - не важно сколько в нем находится элементов (2, 200, 1000000) скорость доступа к элементу будет постоянна т.е при поиске элемента будет затрачиваться одно и то же время не зависимо от размера списка или кортежа это примерно 0.017 секунды. Рекомендуется использовать tuple поскольку они оптимизированы. при старте python сразу знает сколько tuple займет места в памяти и сразу резервирует место в памяти под tuple. А при создании list python каждый раз обращается к ОС и просит выделить память. Кроме того пустой list занимает 56 байт, а tuple 40 байт. Очевидно, что и python во время выполнения программы создает кучу кортежей и списков и при правильном использовании tuple будет экономиться время и ПАМЯТЬ. Но использовать tuple надо обоснованно. И не надо заменять список кортежем там, где идет изменение размера. Так же если заранее известен размер списка, то лучше его создать сразу заполнив нулевыми значениями и в этом случае не использовать append. Кроме того можно посмотреть как создаются списки - например на List() будет затрачено ровно в 2 раза больше времени чем на создание списка через [] В общем я не особо разбираясь в программировании начал бы искать от сюда.