当你删除元素时,Perl中的哈希表是否会缩小?

8

当你删除元素时,Perl中的哈希表是否会缩小?

更具体地说,我继承了一个Perl程序,它会解析一个巨大的文件(1 GB),并加载一个哈希表。它会对另一个文件执行相同的操作,然后比较不同的元素。在此过程中,内存消耗非常大,即使我添加了在使用哈希元素后删除它们,内存消耗似乎也没有受到影响。

该脚本非常缓慢,而且内存占用很高。我知道它设计得不好,但有关哈希表内存使用情况的任何想法吗?

6个回答

11
你可能想要查看类似DBM::Deep这样的东西。它做了那个Michael提到的关于绑定的事情,所以你不必考虑它。所有的数据都存储在磁盘上而不是内存中。它几乎需要一个更高级的数据库服务器。
此外,如果你想追踪性能瓶颈,可以查看Devel::NYTProf,这是Perl性能分析中的新热点,起源于纽约时报。

7
一般来说,Perl无法将内存返回给操作系统。但是它可以在内部重新使用内存,从而减少程序所需的内存量。
请参阅perlfaq3:如何释放数组或哈希表以使我的程序缩小? 如果哈希表使用的内存过多(即>物理内存),则可以将它们绑定到磁盘上的文件中。这将大大减少您的内存使用量,但请注意,访问磁盘上的结构比访问内存中的结构要慢得多。(磁盘抖动也是如此。)

5
如果你的哈希表非常庞大,更好的策略是使用磁盘哈希表,并让操作系统负责将数据载入和载出内存。我特别喜欢使用 Berkeley DB 来存储大型哈希表,而 Perl 的 BerkeleyDB 模块提供了完整的接口,包括绑定 API。 DBM::Deep 也可以作为哈希表的替代品,但它依赖于自己的格式。如果你需要让其他(非 Perl)系统读取你的结构,这可能会很麻烦。

5
关于具体问题:删除哈希键并不能减少程序的内存消耗。
关于更一般的情况:绝大多数程序和语言会继续保留之前使用过但当前未使用的内存。这是因为向操作系统请求分配内存是一个相对较慢的操作,所以它们会保留这些内存以防待会儿再次需要使用。
因此,如果你想改善这种情况,就需要减少程序需要的峰值内存量,可以通过修改算法,使其不需要一次性访问太多数据;或者使用磁盘存储(如上述的DBM::Deep);或者释放不需要的变量空间回收给perl(让它们超出作用域或将它们设置为undef),以便重复使用。

4

如果第二个文件中的输入只需要读取一次,那么你可能可以将内存使用量减少一半。

根据你的算法,你甚至可以同时保持两个文件句柄和一个小的未使用值哈希表在内存中。例如,合并或比较排序数据 - 您只需要保持每个文件的当前行,并在进行比较时互相比较,跳过直到cmp改变为止。

另一种方法可能是进行多次传递,特别是如果您的计算机有一个或多个空闲核心。打开读取管道,并使子进程以可管理的预组织块向您提供数据。

对于更通用的算法,您只能通过将其交换为磁盘速度的成本来避免支付内存大小的代价。

在大多数情况下,将每个数据源加载到内存中只在开发时间上获胜 - 然后当N变大时,您将付出其占用空间和/或速度的代价。


4

解决方法:fork一个子进程来分配所有的内存。让它在完成任务后返回一些汇总信息;当fork出的进程死亡时,它的内存也会随之释放。这可能有点麻烦,但对于某些情况是有效的。一个适用的例子是,如果您正在处理许多文件,每次只处理一个文件,只有少量的大文件需要处理,并且不需要保留太多中间状态。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接