MaiBot
MaiBot copied to clipboard
Maibot内存泄露问题
检查项
- [x] 我确认此问题在所有分支的最新版本中依旧存在
- [x] 我确认在 Issues 列表中并无其他人已经提出过与此问题相同或相似的问题
- [ ] 我使用了 Docker
使用的分支
main
具体版本号
0.11.5
遇到的问题
在Debian12系统中,主程序会不断占用内存直至系统内存被塞满导致程序崩溃,下方报错信息为deepwiki的分析
报错信息
根据我对代码库的分析,我找到了导致内存泄漏的主要原因:
主要问题:last_messages 字典无限增长
在 ChatManager 类中,存在一个名为 last_messages 的字典,用于存储每个聊天流的最后一条消息。 1
每次收到消息时,register_message 方法都会将消息添加到这个字典中: 2
关键问题是:这个字典中的消息从未被清理或删除。随着机器人运行时间的增长,每个新的 stream_id 都会在字典中添加一个条目,并且这些条目会永久保留在内存中。
内存泄漏的影响
在 bot.py 中,每次处理消息时都会调用 register_message: 3
这意味着:
- 每个活跃的聊天流(群组或私聊)都会在
last_messages中保留一条消息 - 如果机器人在大量群组中活跃,或处理大量私聊,这个字典会持续增长
MessageRecv对象本身可能包含大量数据(消息内容、用户信息、上下文等)- 没有任何机制来限制字典的大小或清理旧条目
与数据库清理的对比
虽然项目中有 MemoryForgetTask 来定期清理数据库中的旧聊天历史记录, 4
但这个任务只清理数据库中的记录,不会清理内存中的 last_messages 字典。
解决建议
要解决这个内存泄漏问题,需要实现以下机制之一:
- 限制字典大小:使用
collections.deque并设置maxlen参数,或实现 LRU 缓存 - 定期清理:添加定时任务,删除长时间未活跃的聊天流的消息
- 使用弱引用:考虑使用
weakref来存储消息引用 - 设置过期时间:为每条消息添加 TTL(生存时间),定期清理过期消息
Notes
- 这个问题在高活跃度的机器人实例中会更快地显现,特别是在 Debian 12 这样的长期运行的服务器环境中
- 内存泄漏是渐进式的,所以可能需要运行一段时间后才会导致系统崩溃
- 虽然代码中有数据库层面的记忆遗忘机制,但内存中的数据结构缺乏相应的清理逻辑
- 建议开发者在
ChatManager类中添加定期清理机制,或限制last_messages和streams字典的大小
Citations
File: src/chat/message_receive/chat_stream.py (L130-130)
self.last_messages: Dict[str, "MessageRecv"] = {} # stream_id -> last_message
File: src/chat/message_receive/chat_stream.py (L162-170)
def register_message(self, message: "MessageRecv"):
"""注册消息到聊天流"""
stream_id = self._generate_stream_id(
message.message_info.platform, # type: ignore
message.message_info.user_info,
message.message_info.group_info,
)
self.last_messages[stream_id] = message
# logger.debug(f"注册消息到聊天流: {stream_id}")
File: src/chat/message_receive/bot.py (L282-282)
get_chat_manager().register_message(message)
File: src/chat/utils/memory_forget_task.py (L17-22)
class MemoryForgetTask(AsyncTask):
"""记忆遗忘任务,每5分钟执行一次"""
def __init__(self):
# 每5分钟执行一次(300秒)
super().__init__(task_name="Memory Forget Task", wait_before_start=0, run_interval=300)
如何重现此问题?
启动程序即会开始无限增长内存
可能造成问题的原因
last_messages 字典无限增长
系统环境
Debian12
Python 版本
Python 3.11
补充信息
No response