FreeBSD上Python字符串的内存使用情况

6 投票
3 回答
692 浏览
提问于 2025-04-16 13:54

我在FreeBSD上观察到Python字符串的内存使用情况有点奇怪。假设我们想创建一个列表,里面放一些字符串,总字符数达到100MB。

l = []
for i in xrange(100000):
    l.append(str(i) * (1000/len(str(i))))

这样做大约会使用100MB的内存,使用'del l'命令可以清除这些内存。

l = []
for i in xrange(20000):
    l.append(str(i) * (5000/len(str(i))))

但是,这个操作却用了165MB的内存。我真的搞不懂为什么会多出这么多内存。[两个列表的大小是一样的]

我使用的是FreeBSD 7.2上的Python 2.6.4。在Linux和Windows上,内存使用量大约只有100MB。

更新:我用'ps aux'来测量内存。这可以在上面的代码片段执行后,通过os.system来运行。同时这些代码是分开执行的。

更新2:看起来FreeBSD在分配内存时是以2的倍数来进行的。所以分配5KB的内存实际上会分配8KB。不过我不太确定。

3 个回答

0

我觉得在FreeBSD系统中,所有的内存地址都必须是2的幂次方对齐的。所以,Python的内存池在内存中有点零散,而不是连续的。

可以试着用其他一些工具来看看有没有什么有趣的东西。

0

这个答案可能在这个故事里。我觉得你看到的可能是一些无法避免的内存管理开销。

正如@Hossein所说,试着把这两个代码片段放在一起运行一次,然后再互换一下。

1

在我看来,可能是内存中的碎片。首先,CPython 中大于 255 字节的内存块会通过 malloc 来分配。你可以参考一下这个链接:

改善 Python 的内存分配器

为了提高性能,大多数内存分配,比如 malloc,返回的地址都是对齐的。举个例子,你不会得到像这样的地址:

0x00003

这个地址没有按照 4 字节对齐,计算机访问这样的内存会很慢。因此,通过 malloc 得到的所有地址应该是:

0x00000
0x00004
0x00008

等等。4 字节对齐只是一个基本的通用规则,实际的对齐策略会因操作系统而异。

你提到的内存使用情况应该是 RSS(不太确定)。对于大多数操作系统,虚拟内存的页面大小是 4K。对于你分配的内存,存储一个 5000 字节的块需要 2 个页面。我们来看一个例子,说明一些内存泄漏的情况。我们假设这里的对齐是 256 字节。

0x00000 {
...       chunk 1
0x01388 }
0x01389 {
...       fragment 1
0x013FF }
0x01400 {
...       chunk 2
0x02788 }
0x02789 {
...       fragment 2
0x027FF }
0x02800 {
...       chunk 3
0x03B88 }
0x03B89 {
...       fragment 3
0x04000 }

如你所见,内存中有很多碎片,它们无法使用,但仍然占用了一个页面的内存空间。我不确定 FreeBSD 的对齐策略是什么,但我认为这可能是由这样的原因造成的。为了在 Python 中高效使用内存,你可以使用一个预先分配的大块 bytearray,并选择一个合适的块大小(你需要测试一下,看看哪个数字最好,这取决于操作系统)。

撰写回答