Linux 解决执行Perl脚本时出现的内存不足错误

Linux 解决执行Perl脚本时出现的内存不足错误,linux,perl,out-of-memory,Linux,Perl,Out Of Memory,我正试图建立一个n-gram语言模型,该模型基于在英语维基百科垃圾堆中找到的前10万个单词。我已经用Java编写的修改过的XML解析器提取出了纯文本,但需要将其转换为vocab文件 为了做到这一点,我找到了一个perl脚本,据说它可以完成这项工作,但缺少关于如何执行的说明。不用说,我是Perl的新手,这是我第一次遇到使用它的需要 当我运行这个脚本时,当我在两台独立的双核机器上使用7.2GB文本文件时,会出现内存不足的错误,这两台机器都有4GB内存,运行的是Ubuntu 10.04和10.10 当

我正试图建立一个n-gram语言模型,该模型基于在英语维基百科垃圾堆中找到的前10万个单词。我已经用Java编写的修改过的XML解析器提取出了纯文本,但需要将其转换为vocab文件

为了做到这一点,我找到了一个perl脚本,据说它可以完成这项工作,但缺少关于如何执行的说明。不用说,我是Perl的新手,这是我第一次遇到使用它的需要

当我运行这个脚本时,当我在两台独立的双核机器上使用7.2GB文本文件时,会出现内存不足的错误,这两台机器都有4GB内存,运行的是Ubuntu 10.04和10.10

当我联系作者时,他说这个脚本在带有4GB内存的MacBook Pro上运行良好,在使用perl 5.12的6.6GB文本文件上执行时,总内存使用量约为78MB。作者还说,脚本逐行读取输入文件,并在内存中创建一个hashmap

剧本是:

#! /usr/bin/perl

use FindBin;
use lib "$FindBin::Bin";

use strict;
require 'english-utils.pl';

## Create a list of words and their frequencies from an input corpus document
## (format: plain text, words separated by spaces, no sentence separators)

## TODO should words with hyphens be expanded? (e.g. three-dimensional)

my %dict;
my $min_len = 3;
my $min_freq = 1;

while (<>) {

    chomp($_);
    my @words = split(" ", $_);

    foreach my $word (@words) {

        # Check validity against regexp and acceptable use of apostrophe

        if ((length($word) >= $min_len) && ($word =~ /^[A-Z][A-Z\'-]+$/) 
        && (index($word,"'") < 0 || allow_apostrophe($word))) {
            $dict{$word}++;
        }
    }

}

# Output words which occur with the $min_freq or more often

foreach my $dictword (keys %dict) {
    if ( $dict{$dictword} >= $min_freq ) {
        print $dictword . "\t" . $dict{$dictword} . "\n";
    }
}
#/usr/bin/perl
使用FindBin;
使用lib“$FindBin::Bin”;
严格使用;
需要“english utils.pl”;
##从输入语料库文档中创建单词及其频率的列表
##(格式:纯文本,用空格分隔的单词,无句子分隔符)
##带连字符的单词应该扩展吗?(如三维)
我的%dict;
我的$min_len=3;
我的$min_freq=1;
而(){
咀嚼(美元);
我的@words=split(“,$”);
foreach我的$word(@words){
#对照regexp和撇号的可接受使用检查有效性
如果((长度($word)>=$min_len)和($word=~/^[A-Z][A-Z\'-]+$/)
&&(索引($word,“”)<0 | |允许撇号($word))){
$dict{$word}++;
}
}
}
#输出使用$min_freq或更频繁出现的字
foreach my$dictword(关键字%dict){
如果($dict{$dictword}>=$min\u freq){
打印$dictword。“\t”。$dict{$dictword}。”\n”;
}
}
我通过
mkvocab.pl corpus.txt从命令行执行此脚本

附带的额外脚本只是一个正则表达式脚本,用于测试撇号的位置以及它们是否符合英语语法规则

我认为内存泄漏是由于不同版本造成的,因为我的机器上安装了5.10。所以我升级到5.14,但错误仍然存在。根据
free-m
,我的系统上大约有1.5GB的可用内存

由于我对语言的语法和结构完全不熟悉,您能否指出问题所在以及问题存在的原因和解决方法。

尝试运行

dos2unix corpus.txt

您可能将整个文件作为一行读取…

如果单词中有重复,则可以将7,2Gb文件加载到哈希中,例如,
发生17000次,等等。不过,这似乎是相当多的

脚本假定文件中的行具有适当的长度。如果您的文件不包含换行符,则将整个文件加载到
$\uu
中的内存中,然后使用
split
将该内存加载加倍,然后将更多的内容添加到哈希中。这会给任何系统带来压力

一种方法是使用空格
作为输入记录分隔符。它将与您使用split所做的大致相同,只不过它将保留其他空格字符,并且不会将多余的空格修剪得很漂亮。例如:

$/ = " ";
while (<>) {
    for my $word ( split ) {  # avoid e.g. "foo\nbar" being considered one word
        if (
              (length($word) >= $min_len) &&
              ($word =~ /^[A-Z][A-Z\'-]+$/) &&
              (index($word,"'") < 0 || allow_apostrophe($word))
        ) {
            $dict{$word}++;
        }
    }
}
$/=”;
而(){
对于我的$word(split){#避免将例如“foo\nbar”视为一个单词
如果(
(长度($word)>=$min_len)&&
($word=~/^[A-Z][A-Z\'-]+$/)&&
(索引($word,“”)<0 | |允许撇号($word))
) {
$dict{$word}++;
}
}
}

假设单词之间有空格(而不是制表符或换行符),那么即使是很长的一行,也可以一口一口地阅读

这可能是一种可能性,因为输出文本仅由编辑器的维度包装…输入文件中是否有长行?如果您的输入文件没有换行符,您将在内存中保存大量数据。即使假设您的单词中有一些重复,您的哈希值也可能非常大。这解决了问题。在一台配备7200 rpm驱动器的双核笔记本电脑上,在没有内存问题的情况下执行大约需要一个小时。谢谢