在没有内存泄漏的情况下在perl中查找校验和的有效方法

时间:2014-06-02 09:44:03

标签: perl

在我的程序中,我需要查找许多文件的校验和。校验和计算在find命令中。

find(sub {
        my $file = $File::Find::name;
        return if ! length($file);
open (FILE, "$file");
my $chksum = md5_base64(<FILE>);
close FILE;
}, "/home/nijin");

以上代码完美无缺。但是如果在/ home / nijin路径中有一个大小的文件,例如6GB,它将把6 GB加载到RAM内存中,并且该过程连续占用6 GB RAM,直到该过程完成。请注意,这是一个备份过程,完成此过程需要12个多小时。所以我将失去6GB,直到完成该过程。最糟糕的情况是由于大量内存使用而导致进程挂起。作为一种选择,我尝试使用File::Map。代码粘贴在下面。

find(sub {
            my $file = $File::Find::name;
            return if ! length($file);
   map_file my $map, "$filename", '<';
    my $chksum = md5_base64($map);
    }, "/home/nijin");

上面的代码也有效但我在使用上面的代码时遇到了分段错误错误。我也试过Sys::Mmap,但问题与第一个问题相同。还有其他选择吗?

2 个答案:

答案 0 :(得分:5)

我会在子进程中运行昂贵的计算。这使父进程保持适当的内存消耗。孩子可以为大文件占用大量内存,但是一旦返回MD5,内存就会返回给操作系统:

#!/usr/bin/perl
use warnings;
use strict;

use Data::Dumper;
use File::Find;
use Digest::MD5 qw{ md5_base64 };

my %md5;

find(sub {
         my $name = $File::Find::name;
         return unless -f;

         my $child_pid = open(my $CMD, '-|') // die "Can't fork: $!";

         if ($child_pid) {                                  # Parent
             $md5{$name} = <$CMD>;
             wait;

         } else {                                           # Child
             open my $IN, '<', $_ or die "$name: $!";
             print md5_base64(<$IN>);
             exit;
         }

     }, shift);

print Dumper \%md5;

答案 1 :(得分:3)

没有理由一次将整个文件读入内存。

您可以通过以下方式以64k块显式处理它:

my $chksum = do {
    open my $fh, '<:raw', $file;
    my $md5 = Digest::MD5->new;
    local $/ = \65536; # Read 64k at once
    while (<$fh>) {
        $md5->add($_);
    }
    $md5->hexdigest;
};
# Do whatever you were going to do with it here

您也可以直接传递文件句柄,但这并不能保证它如何处理它:

my $chksum = do {
    open my $fh, '<:raw', $file;
    Digest::MD5->new->addfile($fh)->hexdigest
};