在perl。哈希如何在内存中存储数据

时间:2010-08-04 00:38:46

标签: perl

我有一个大的xml文件,解析它会消耗大量内存 因为我相信大部分是由于文件中有很多用户名 我将每个用户名的长度从~28字节更改为10字节 并再次运行。但它仍然需要几乎相同的内存量 到目前为止,xml文件是用SAX解析的,在处理过程中,结果是 存储在哈希结构中,如下所示:
$this->{'date'}->{'school 1'}->{$class}->{$student}...

为什么在减少学生姓名长度后记忆仍然如此之多?可能吗 当数据存储在哈希内存中时。无论字符串长度多长,都会有很多开销?

3 个答案:

答案 0 :(得分:5)

Perl哈希使用一种称为桶链的技术。所有具有相同哈希值的密钥(请参阅hv.h中的宏PERL_HASH_INTERNAL)都在同一个“存储桶”中,即线性列表。

根据perldata文档

  

如果在标量上下文中评估散列,则在散列为空时返回false。如果有任何键/值对,则返回true;更准确地说,返回的值是一个字符串,由使用的桶数和分配的桶数组成,用斜杠分隔。这非常有用,只是为了找出Perl的内部哈希算法是否在您的数据集上表现不佳。例如,您在哈希值中粘贴了10,000个内容,但在标量上下文中评估%HASH会显示"1/16",这意味着只触摸了十六个桶中的一个,并且可能包含所有10,000个项目。这不应该发生。如果在标量上下文中计算绑定哈希值,则会导致致命错误,因为此存储桶使用信息当前不适用于绑定哈希值。

要查看数据集是否具有病态分布,您可以检查标量上下文中的各个级别,例如

print scalar(%$this), "\n",
      scalar(%{ $this->{date} }), "\n",
      scalar(%{ $this->{date}{"school 1"} }), "\n",
      ...

有关过时的概述,请参阅perl.com上的How Hashes Really Work

学生姓名长度的适度减少,四级关键,不会产生显着差异。通常,perl实现强烈倾向于在问题上抛出内存。这不是你父亲的FORTRAN。

答案 1 :(得分:0)

是的 - 有很多开销。如果可能的话,不要将数据存储为完整的树,特别是因为您正在使用SAX解析器,这使您免于DOM的强制要求。

如果你必须存储整个树,一种可能的解决方法是存储数组数组 - 例如将所有学生姓名存储在一个数组中(例如,将“mary123456”存储在$students[11]中,然后将...->{"mary123456"}的哈希值存储为->[11]

由于额外的间接层,它会增加处理时间,但由于内存使用量减少而减少/抖动可能会减少。

另一种选择是使用与文件绑定的哈希值,当然,由于磁盘IO瓶颈,它会非常慢。

答案 2 :(得分:0)

使用可以报告各种数据结构有多大的Devel::Size模块可能很有用:

use Devel::Size qw(total_size);
print "Total Size is: ".total_size($hashref)."\n";