2010-08-04 42 views
4

我有一个很大的XML文件并解析它会消耗大量的内存。
因为我相信大部分是由于文件中的大量用户名。
我将每个用户名的长度从〜28字节改为10字节。
并再次运行。但它仍然需要几乎相同数量的内存。
XML文件是迄今为止解析使用SAX和处理过程中,其结果是 存储在哈希结构,像这样:
$this->{'date'}->{'school 1'}->{$class}->{$student}...。哈希如何在内存中存储数据

为什么记忆依然那么多之后,我减轻学生名字的长度?当数据存储在散列存储器中时,有可能是 。不管字符串的长度是多少,都有很多开销?

+0

是XML文件,以及有多少内存被使用多大的程序? – Ether 2010-08-04 00:43:13

+0

是的,即使使用较短的字符串,也会有很多开销。 – ysth 2010-08-04 00:53:07

+0

我有20个xml文件,每个文件都是0.25GB,通过将学生名称字符串从26Byte减少到10个字节,每个xml文件的大小现在变为0.185GB。它使用〜2GB内存为64位perl,并且在我缩短字符串长度后仍然使用〜2GB内存,每个学生的格式如下: ' mary123456 user399517 2010-08-04 01:04:25

回答

5

Perl的哈希使用一种称为bucket-chaining的技术。所有具有相同散列的密钥(请参阅中的宏)进入同一个“桶”,一个线性列表。

按照perldata文档

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

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

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

对于有些过时概述,请参阅How Hashes Really Work在perl.com。

学生姓名,四级关键字长度的适度减少不会产生重大影响。一般来说,perl实现对于抛出问题存在强烈的偏见。这不是你父亲的FORTRAN。

+0

非常有帮助。非常感谢你。 – user399517 2010-08-04 21:13:17

0

是的 - 有很多开销。如果可能的话,不要将数据存储为完整的树,特别是因为您使用的是SAX解析器,它可以让您免于使用DOM解析器的必要性。

如果你必须存储整个树,一个可能的解决方法是存储数组的数组 - 例如,您存储所有学生的名字在阵列(,说“mary123456”被存储在$students[11],然后存储将是...->{"mary123456"}->[11],而不是一个哈希值。

它会增加处理时间,由于间接的额外层,但可能会降低由于使用更少的内存,从而少交换/抖动。

另一种选择是使用哈希绑文件,虽然这将是非常缓慢的,由于磁盘IO瓶颈,当然。

+0

嗨,DVK thx再次。 1. SAX将在下一个元素向右移动时释放数据?到目前为止,我的SAX处理程序将数据复制到我的散列,并且我相信所有的内存都归于我的散列而不是由sax创建的数据结构。纠正我,如果我错了。 2.一旦不使用它,我已经从我的哈希中删除了一些元素,但这还不够。我不明白你的数组阵列。似乎你建议创建$学生[11] ='mary123456',然后$ this ... {'mary123456'} = 11,那么你不会减少内存,但会引入更多的内存吗?我曾试过领带档案。 222让我的老板很快乐。 – user399517 2010-08-04 01:50:50

0

可能使用Devel::Size模块能够回报的各种数据结构有多大是有用的:

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

谢谢。我听说Devel :: Size本身消耗大量内存。但很高兴知道,并会尝试。 – user399517 2010-08-10 05:22:21