为什么 Ruby 使用这么多内存来存储大型数组?

Why does Ruby use so much memory storing large arrays?

过去几天我一直在从事一个项目,该项目涉及读取较大的文件。具体来说,它逐行读取它们以解析数据以插入到数据库中。

虽然 运行 对这些文件进行了测试,但我发现对于一个 400MB 的文件,Ruby 分配了超过 1.2GB 的内存;大约是文件本身占用量的 3 倍。更麻烦的是,一旦内存被占用,Ruby 就不想让大部分内存消失。手动 运行 GC 仅回收它分配的大约三分之一的内存,这意味着一个 400MB 的文件分成几行占用超过 800MB 的内存。

这让我很困惑,我想知道我是否做错了什么。这是我复制问题的代码:

text = File.read("somefile.txt").split("\n")

我看不出数组中的行如何使内存中的大小翻倍。

在另一种情况下,用 1000 万个字符填充数组会导致每 1 字节数据占用 40 字节的内存,尽管我已准备好将此考虑到字符串元数据。

作为参考,我在 Windows 8.

上使用 Ruby 2.1.5p273 [i386-mingw32]

此外,在我得到答案告诉我以另一种方式阅读台词之前:我已经知道一些替代方案。这只是一个关于内存消耗的问题。

Ruby 中的所有内容都是一个对象,在 C 中是一个 RVALUE(一个描述对象并保存指向为其值分配的内存的指针的结构),IIRC 在 64- 上是 40 字节bit machine,加上堆内存为RVALUE的值。

Ruby 在 "heaps"(不是 堆)中分配内存,这是一块存储 RVALUE 的内存。一个堆有 N 个槽,其中 1 个槽可以容纳一个 RVALUE。当你填满一个堆时,Ruby 将 运行 GC 尝试释放插槽,如果不能,它将分配另一个堆来容纳额外的 RVALUE。很难让 Ruby 释放分配后的堆,因为它必须完全清空才能被收集,并且 Ruby 不断分配新对象。

一般来说,您应该避免分配大量不可释放的对象,因为您最终会分配多个 RVALUE 堆,Ruby 然后很难放手。