2010-07-29 22 views
6

Tôi đã làm việc trên một dự án perl tại nơi làm việc và gặp phải một sự rò rỉ bộ nhớ lạ. Tôi đã luộc xuống nguồn gốc của vấn đề của tôi vào một ví dụ contrived:Bản đồ Perl/rò rỉ bộ nhớ grep

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

# takes: an array reference 
# returns: 1 
sub g { 
    my ($a) = @_; 
    return 1; 
} 

# takes: nothing 
# returns: the result of applying g on an array reference 
sub f { 
    my @a = ('a') x 131072; # allocate roughly a megabyte 
    return g(\@a); 
} 

# causes a leak: 
#map { f($_) } (1..100000); 

# loop equivalent to map, no leak: 
#my @b; 
#for my $i (1..100000) { 
# push @b, f($_); 
#} 

# causes a leak: 
#grep { f($_) } (1..100000); 

# loop equivalent to grep, no leak: 
#my @b; 
#for my $i (1..100000) { 
# push @b, $i if f($_); 
#} 

bỏ chú thích 1 trong 4 khối mã (dưới chương trình con) tại một thời điểm và chạy kịch bản trong khi giám sát việc sử dụng bộ nhớ của nó. Trên máy tính của tôi, mã sử dụng grep hoặc bản đồ xuất hiện để gây rò rỉ bộ nhớ, trong khi "vòng lặp tương đương" thì không. Phiên bản perl của tôi là v5.10.1 và tôi đang chạy Ubuntu.

Tôi tin rằng đây có thể là một lỗi trong perl, nhưng tôi không muốn nhảy đến một kết luận quyết liệt mà không có ý kiến ​​khác về nguyên nhân có thể là gì. Bất cứ ai có thể giải thích nếu hành vi này là chính xác?

Cảm ơn

Trả lời

2

Tôi không biết đó có phải là rò rỉ bộ nhớ như vậy hay không. Nếu tôi giảm giá trị trên cùng của vòng lặp của bạn (giả sử, từ 100000 đến 100), tôi có thể sử dụng các biểu thức map/grep nhiều lần mà không làm mất bộ nhớ.

Thay vào đó, có vẻ như nhiều khả năng mapgrep là các hoạt động nguyên tử khi nói đến quản lý bộ nhớ, rằng perl không thực hiện thu gom rác ở giữa các hoạt động đó.

Perl 5.12.0 (và 5.8.9) có vẻ mạnh mẽ hơn một chút đối với các loại biểu thức này (nhưng chúng cũng có vẻ chậm hơn).

1

Thực sự là vậy. Nhưng để chứng minh điều đó, bạn phải đặt trong khi (1) {} biểu hiện nghi ngờ - trong perl, bộ nhớ mà một khi được mua lại không bao giờ quay trở lại OS (nhưng có thể được tái sử dụng bởi chính perl). Tôi đã chạy mã với

while (1) {grep {f ($ _)} (1..100000)}

dưới 5.8.8 và nó không ngừng phát triển về quy mô - vì vậy, đó là một sự rò rỉ .