Perl 使用WWW::Mechanize执行重复查询时内存泄漏
我试图在我的程序中找到内存泄漏。我已经找到了漏洞的来源,但我无法修复它 该程序读取与维基百科上的每个染色体相连的每个基因页面 该程序在每个基因页面上提取我感兴趣的信息,然后移动到下一个基因页面,依此类推 一旦到达当前染色体的基因列表的末尾,它就会移动到下一条染色体上,直到完成每一页 这个程序在我的电脑上运行到大约2-3周前。从那时起,它开始出现这个问题 我一直在使用Perl 使用WWW::Mechanize执行重复查询时内存泄漏,perl,memory-leaks,wikipedia-api,www-mechanize,Perl,Memory Leaks,Wikipedia Api,Www Mechanize,我试图在我的程序中找到内存泄漏。我已经找到了漏洞的来源,但我无法修复它 该程序读取与维基百科上的每个染色体相连的每个基因页面 该程序在每个基因页面上提取我感兴趣的信息,然后移动到下一个基因页面,依此类推 一旦到达当前染色体的基因列表的末尾,它就会移动到下一条染色体上,直到完成每一页 这个程序在我的电脑上运行到大约2-3周前。从那时起,它开始出现这个问题 我一直在使用top进行监控,随着程序的运行,内存使用明显增加,直到达到临界点,我的计算机崩溃 根据请求,我提供可编译的代码。我是从21号染色体开
top
进行监控,随着程序的运行,内存使用明显增加,直到达到临界点,我的计算机崩溃
根据请求,我提供可编译的代码。我是从21号染色体开始的,因为这一条的页数最少,因此花的时间最少。在这个代码片段中,内存使用仍然在递增,所以希望这就足够了!此外,eval语句也在其中,因为查询WikipediaAPI有时不会返回任何内容,而不是预期的JSON。eval函数允许我绕过这个问题,而不会让程序死掉
我的(更新的)代码
这段代码有一个更大的组件,但我排除了它,因为我知道这是问题的根源所在
使用WWW::Mechanize的while
循环部分
my $response = $mech->get($url)
已连接到内存泄漏
如果我删除该组件并运行该程序,内存使用保持不变,然后将其添加回显示内存再次增量增加
Perl版本:5.24.1
系统:Ubuntu 16.04
编辑:@Borodin谢谢你如此详尽的回复!不幸的是,我仍然注意到我的电脑内存泄漏,这让我怀疑是否还有更大的问题
它仍然会逐渐占用内存,目前我的电脑还可以,但当我运行包括一些网页抓取在内的完整程序时,我不知道我的电脑是否能够满足需要
有一点可能与此相关——我的电脑有一个奇怪的问题,它有时无法完全下载文件(尽管下载已完成,但文件被截断)。当我运行你的程序时,我经常遇到这样的错误:
**解析JSON字符串时出现意外的字符串结尾,字符偏移量5506(在“(字符串结尾)”之前)**
这似乎与我遇到的问题有关,我想知道这是否会导致内存泄漏问题?您没有使用WWW::Mechanize
中LWP::UserAgent
没有提供的任何部分,因此我建议您遵循后者
下面是一些与您自己的程序几乎相同的工作代码。对我来说,它没有任何内存泄漏
请询问您是否需要任何解释;内容太多,无法贯穿整个节目
#!/usr/bin/env perl
use strict;
use warnings 'all';
use URI;
use URI::QueryParam;
use LWP;
use JSON::XS qw(decode_json);
STDOUT->autoflush;
my $api_root = URI->new( 'http://en.wikipedia.org/w/api.php' );
my @chromosomes = ( 1 .. 22, qw/ M Y X/ );
my $ua = LWP::UserAgent->new;
for my $chrom ( @chromosomes[20..$#chromosomes] ) {
#print "The chromosome is $chrom\n";
my $query = {
action => 'query',
format => 'json',
list => 'categorymembers',
cmtitle => "Category:Genes on human chromosome $chrom",
cmlimit => 'max',
};
my $url = $api_root->clone;
$url->query_form( $query );
my @gene_pages;
while () {
my $resp = $ua->get( $url );
die $resp->status_line unless $resp->is_success;
# J Source of malformed JSON string error
my $data = decode_json( $resp->decoded_content );
my $query = $data->{query};
my $continue = $data->{continue};
push @gene_pages, @{ $query->{categorymembers} };
# Adapted code to new format for continuing queries
last unless $continue;
$url->query_param( cmcontinue => $continue->{cmcontinue} );
}
printf "Processing %d gene pages for chromosome %s\n",
scalar @gene_pages,
$chrom;
my $gene_count;
for my $gene_page ( @gene_pages ) {
++$gene_count;
my $url = $api_root->clone;
my $query = {
action => 'query',
prop => 'revisions',
format => 'json',
rvprop => 'content|tags|timestamp',
pageids => $gene_page->{pageid}
};
$url->query_form( $query );
# print "Requesting: $url\n";
my $resp = $ua->get( $url );
die $resp->status_line unless $resp->is_success;
my $content = $resp->decoded_content;
my $data = decode_json( $content ); # J Source of malformed JSON string error
print "$gene_count gene pages complete\n" unless $gene_count % 10;
}
print "There were $gene_count genes found for chromosome $chrom\n";
}
Mechanize保留它访问的每个页面的历史记录,默认情况下,它实际上是无限的。尝试将stack\u depth
选项设置为较低的值,看看是否有帮助。感谢您的快速回复。我试着像这样使用堆栈深度:my$mech=WWW::Mechanize->new()$机械->堆叠深度(0);内存使用仍然显示相同的行为。WWW::Mechanize可能不是罪魁祸首吗?您必须始终在编写的每个Perl程序的顶部使用strict
和使用警告“all”
。这是调试的第一级,应该在你请求他人帮助之前采用。@simbabque:我不喜欢和,它们试图做类似的事情,主要是因为我每次都要查看它们所做的事情common::sense
似乎是由希望Perl完全是另一种语言的人编写的。但事实是,我没有注意到use
语句,是的,它涵盖了一些功能,但是使用严格的“refs”
是必不可少的,因为符号引用是一个可怕的想法。当
时,它也给定
…,这是一个坏消息default@Borodinsense.pm.PL,其中$ARGV[0]
设置为“sense.pm”。它为执行安装的perl版本生成适当的代码,将其写入sense.pm
,并将sense.pm
重命名为sense.pm
。
#!/usr/bin/env perl
use strict;
use warnings 'all';
use URI;
use URI::QueryParam;
use LWP;
use JSON::XS qw(decode_json);
STDOUT->autoflush;
my $api_root = URI->new( 'http://en.wikipedia.org/w/api.php' );
my @chromosomes = ( 1 .. 22, qw/ M Y X/ );
my $ua = LWP::UserAgent->new;
for my $chrom ( @chromosomes[20..$#chromosomes] ) {
#print "The chromosome is $chrom\n";
my $query = {
action => 'query',
format => 'json',
list => 'categorymembers',
cmtitle => "Category:Genes on human chromosome $chrom",
cmlimit => 'max',
};
my $url = $api_root->clone;
$url->query_form( $query );
my @gene_pages;
while () {
my $resp = $ua->get( $url );
die $resp->status_line unless $resp->is_success;
# J Source of malformed JSON string error
my $data = decode_json( $resp->decoded_content );
my $query = $data->{query};
my $continue = $data->{continue};
push @gene_pages, @{ $query->{categorymembers} };
# Adapted code to new format for continuing queries
last unless $continue;
$url->query_param( cmcontinue => $continue->{cmcontinue} );
}
printf "Processing %d gene pages for chromosome %s\n",
scalar @gene_pages,
$chrom;
my $gene_count;
for my $gene_page ( @gene_pages ) {
++$gene_count;
my $url = $api_root->clone;
my $query = {
action => 'query',
prop => 'revisions',
format => 'json',
rvprop => 'content|tags|timestamp',
pageids => $gene_page->{pageid}
};
$url->query_form( $query );
# print "Requesting: $url\n";
my $resp = $ua->get( $url );
die $resp->status_line unless $resp->is_success;
my $content = $resp->decoded_content;
my $data = decode_json( $content ); # J Source of malformed JSON string error
print "$gene_count gene pages complete\n" unless $gene_count % 10;
}
print "There were $gene_count genes found for chromosome $chrom\n";
}