gc的性能问题

在优化日志落盘的任务里,为了避免消费日志队列过慢导致爆队列,其中一个优化是快速消费队列并全部缓存到 deque 里,再慢慢落盘

但测试时发现,虽然理论上 dequeappend 是 O(1) 的,但实际表现是 append 时不时会变慢(体现为消费队列并 append 变慢导致队列爆掉),且随着 deque 变大,对应的延迟会变高

这个问题表现类似 is there a way to circumvent python list append becoming progressively slower,所以猜测可能也是 gc 导致的,禁用 gc 后确实不会变慢了,但随后发现引入了内存泄露,即虽然 deque 里缓存的元素被消费完了,但进程内存用量不会下降

由于 gc 只被用于回收有循环引用的对象,所以猜测是项目里的某些对象有循环引用,定位到了如下代码:

class Foo:
    @property
    def bar(self):
        try:
            return self._bar
        except AttributeError:
            self._bar = self.c_bar.contents
            return self._bar

其中 c_bar 是一个 ctypes.POINTER,在命中 AttributeError 时的逻辑会使 self._bar 引用 self.c_bar,产生循环引用,改掉这里后内存泄露消失