diff --git a/src/blrec/core/stream_recorder.py b/src/blrec/core/stream_recorder.py index aece0cf..287f4b3 100644 --- a/src/blrec/core/stream_recorder.py +++ b/src/blrec/core/stream_recorder.py @@ -8,6 +8,7 @@ from blrec.bili.typing import QualityNumber, StreamFormat from blrec.event.event_emitter import EventEmitter from blrec.flv.operators import MetaData, StreamProfile from blrec.setting.typing import RecordingMode +from blrec.utils.libc import malloc_trim from blrec.utils.mixins import AsyncStoppableMixin from .flv_stream_recorder_impl import FLVStreamRecorderImpl @@ -255,6 +256,7 @@ class StreamRecorder( async def _do_stop(self) -> None: await self._impl.stop() + malloc_trim(0) async def on_video_file_created(self, path: str, record_start_time: int) -> None: await self._emit('video_file_created', path, record_start_time) diff --git a/src/blrec/task/task_manager.py b/src/blrec/task/task_manager.py index eb8ead6..e129fc8 100644 --- a/src/blrec/task/task_manager.py +++ b/src/blrec/task/task_manager.py @@ -7,6 +7,8 @@ from typing import TYPE_CHECKING, Dict, Iterator, Optional import aiohttp from tenacity import retry, retry_if_exception_type, stop_after_delay, wait_exponential +from blrec.utils.libc import malloc_trim + from ..bili.exceptions import ApiRequestError from ..exception import NotFoundError, submit_exception from ..flv.operators import MetaData, StreamProfile @@ -17,8 +19,8 @@ if TYPE_CHECKING: from ..setting import SettingsManager from ..setting import ( - DanmakuSettings, BiliApiSettings, + DanmakuSettings, HeaderSettings, OutputSettings, PostprocessingSettings, @@ -57,6 +59,7 @@ class RecordTaskManager: return await asyncio.wait([t.destroy() for t in self._tasks.values() if t.ready]) self._tasks.clear() + malloc_trim(0) logger.info('Successfully destroyed all task') def has_task(self, room_id: int) -> bool: @@ -115,11 +118,13 @@ class RecordTaskManager: await task.disable_monitor() await task.destroy() del self._tasks[room_id] + malloc_trim(0) async def remove_all_tasks(self) -> None: coros = [self.remove_task(i) for i, t in self._tasks.items() if t.ready] if coros: await asyncio.wait(coros) + malloc_trim(0) async def start_task(self, room_id: int) -> None: task = self._get_task(room_id, check_ready=True) diff --git a/src/blrec/utils/libc.py b/src/blrec/utils/libc.py new file mode 100644 index 0000000..6771ac8 --- /dev/null +++ b/src/blrec/utils/libc.py @@ -0,0 +1,16 @@ +from ctypes import cdll +from ctypes.util import find_library + +lib_name = find_library('c') +if not lib_name: + libc = None +else: + libc = cdll.LoadLibrary(lib_name) + + +def malloc_trim(pad: int) -> bool: + """Release free memory from the heap""" + assert pad >= 0, 'pad must be >= 0' + if libc is None: + return False + return libc.malloc_trim(pad) == 1