Не могу понять почему накопительно увеличивается потребление оперативной памяти

Каковы примерные причины накопительного увеличения оперативной памяти сервера?

код использую для бота дискорд, бот изначально запускается, и хост показывает потребление памяти в пределах 300-350 мб, но спустя 1-2 часа, это значение доходит до 1.5гб.

Попробовал использовать gc.collect(), но это результата не дает. то, что это та часть кода, которая засоряет оперативную память, выяснил путем комментирования разных команд, и эмпирическим путем получил то, что при комментировании этой части кода оперативная память стабильно стоит в 145-150 на протяжении более 12 часов.

def load_last_row_count():
    try:
        with open('monitor_count.json', 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return 0


def save_last_row_count(last_row_count):
    with open('monitor_count.json', 'w') as f:
        json.dump(last_row_count, f)


last_row_count = load_last_row_count()

@tasks.loop(seconds=10)
async def monitor_sheet():
    global last_row_count

    sheet_id = sheet_URL
    range_name = sheet_range_name

    try:
        values = get_sheet_values(sheet_id, range_name, SERVICE_ACCOUNT_FILE, SCOPES)
        current_row_count = len(values)

        if last_row_count == current_row_count:
            return

        for i in range(last_row_count, current_row_count):
            new_entry = values[i]
            if new_entry[5] == "HiTech":
                message = format_message(new_entry)
                await send_discord_notification(bot, MONITOR_CHANNEL_ID, message)

        last_row_count = current_row_count
        save_last_row_count(last_row_count)

    except Exception as e:
        print(f"Ошибка при мониторинге таблицы: {e}")
        await send_discord_notification(bot, MONITOR_CHANNEL_ID, f"Ошибка при мониторинге таблицы: {e}")


@bot.event
async def on_ready():
    current_time = datetime.now().strftime("%H:%M:%S")
    print(f'Подключение успешно {bot.user} в {current_time}')
    await send_discord_notification(bot, MONITOR_CHANNEL_ID, f"Подключено в {current_time}")
    monitor_sheet.start()

объяснение кода:
бот обращается каждые 10 секунд к гугл таблице, и сверяет количество строк в момент обращения с количеством строк в прошлое обращение, если есть разница между количеством, то он отправляет эти строки мне в дискорд, с учетом условия, в 6 столбце должно быть написано слово HiTech.

также в момент нового запроса он записывает количество строк в .json файл, чтобы сверить его в следующем запросе.

на всякий случай прикреплю еще все функции, которые используются:

def get_sheet_values(sheet_id, range_name, service_account_file, scopes):
    creds = service_account.Credentials.from_service_account_file(service_account_file, scopes=scopes)
    service = build('sheets', 'v4', credentials=creds)
    sheet = service.spreadsheets()
    result = sheet.values().get(spreadsheetId=sheet_id, range=range_name).execute()
    values = result.get('values', [])
    return values


def format_message(entry):
    
    fields = ["Дата и время заполнения заявки", "e-mail", "Игровой ник", "Имя", "Для связи", "Сервер", "Номер сервера",
              "Опыт", "Время от МСК", "Сколько готов играть", "Знание модов", "О себе"]
    values = [entry[i].strip() if i < len(entry) and entry[i].strip() else "*данные не заполнены*" for i in
              range(len(fields))]

    formatted_message = (
        f"# Вот это заявочка ? \n"
        f"{fields[2]}: **{values[2]}**\n"
        f"{fields[3]}: **{values[3]}**\n"
        f"{fields[0]}: **{values[0]}**\n"
        f"{fields[1]}: **{values[1]}**\n"
        f"{fields[4]}: **{values[4]}**\n"
        f"{fields[5]}: **{values[5]}**\n"
        f"{fields[6]}: **{values[6]}**\n"
        f"{fields[7]}: **{values[7]}**\n"
        f"{fields[8]}: **{values[8]}**\n"
        f"{fields[9]}: **{values[9]}**\n"
        f"{fields[10]}: **{values[10]}**\n"
        f"{fields[11]}: **{values[11]}**"

    )
    return formatted_message


async def send_discord_notification(bot: commands.Bot, channel_id: int, message):
    channel = bot.get_channel(channel_id)
    if channel:
        try:
            await channel.send(message)
        except Exception as e:
            print(f"Ошибка при отправке сообщения в канал: {e}")
    else:
        print("Не удалось найти канал для отправки уведомления.")

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


Ответы (3 шт):

Автор решения: AnnaBazueva

Попробуйте отказаться от объявления global в async которую будете изменять.

def load_last_row_count():
    try:
        with open('monitor_count.json', 'r') as f:
            return json.load(f)
    except FileNotFoundError:
        return 0


def save_last_row_count(last_row_count):
    with open('monitor_count.json', 'w') as f:
        json.dump(last_row_count, f)


@tasks.loop(seconds=10)
async def monitor_sheet():

    last_row_count = load_last_row_count()

global - первое что бросается в глаза.

→ Ссылка
Автор решения: CrazyElf

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

То есть вам нужно вынести этот кусок кода в отдельную функцию, которую вызывать в самом начале один раз, а в остальные функции передать уже готовую переменную sheets, которой дальше и пользоваться:

def GetSheet():
    creds = service_account.Credentials.from_service_account_file(service_account_file, scopes=scopes)
    service = build('sheets', 'v4', credentials=creds)
    sheet = service.spreadsheets()
    return sheet

А вот здесь пишут, что проблема скорее всего в вызове build, то есть, возможно, достаточно один раз создать service, а не sheet.

→ Ссылка
Автор решения: Dmitriy Nasyrov

Помогло создание класса и правильный вызов. Утечка прекращена:

class GoogleSheetAPI:
    def __init__(self, service_account_file, scopes):
        self.creds = service_account.Credentials.from_service_account_file(service_account_file, scopes=scopes)
        self.service = build('sheets', 'v4', credentials=self.creds)
        self.sheet = self.service.spreadsheets()

    def get_sheet_values(self, sheet_id, range_name):
        result = self.sheet.values().get(spreadsheetId=sheet_id, range=range_name).execute()
        values = result.get('values', [])
        return values

ну и использование:

google_sheet_api = GoogleSheetAPI(service_account_file, scopes)
values = google_sheet_api.get_sheet_values(sheet_id, range_name)

Вот это нужно вызывать один раз:

google_sheet_api = GoogleSheetAPI(service_account_file, scopes)

А дальше каждый раз, соответственно:

values = google_sheet_api.get_sheet_values(sheet_id, range_name)
→ Ссылка