代码之家  ›  专栏  ›  技术社区  ›  Aaron

如何调试Perl CGI脚本中可能的内存泄漏?

  •  2
  • Aaron  · 技术社区  · 16 年前

    我有一个在Apache上运行的传统Perl CGI页面,它处理大量Excel电子表格数据,并根据需要添加到数据库中。它以数据组的形式进行处理,每组数据被发送到数据库。

    通过查看(复杂的)代码,我找不到内存泄漏可能发生的位置。我可以使用一些工具来确定内存在哪里?

    3 回复  |  直到 16 年前
        1
  •  2
  •   brian d foy    16 年前

    简单的回答是,做你很糟糕。没有一个好的,随时可用的程序,你可以运行得到答案。很抱歉,我不能提供更多的帮助,但是在没有看到任何代码等的情况下,真的没有任何人可以提供更好的建议。

    首先,在web服务器之外运行该程序。如果您仍然从命令行看到问题,请高兴:您只是(大部分)排除了web服务器的问题。这可能需要一点工作来制作一个包装器脚本来设置web环境,但由于不需要重新启动服务器等来重置环境,因此它最终会变得容易得多。

    如果你不能在服务器之外复制问题,你仍然可以做我接下来建议的事情,这只是更烦人而已。如果这是一个Web服务器问题,而不是来自命令行的问题,那么该任务将成为发现这两者之间差异的任务。我遇到过这样的情况。

    如果web服务器没有问题,就开始将脚本一分为二,就像处理调试问题一样。如果您启用了日志记录功能,请将其打开并观察程序运行,同时记录其实际内存使用情况。什么时候爆炸?听起来好像你已经把范围缩小到了一些数据库调用。如果您能够从命令行或调试器运行此操作,我会在内存增加前后找到一对合适的断点,并逐渐将它们放在一起。您可以使用以下模块: Devel::Size 查看您怀疑的数据结构的内存大小。

    从那开始,它只是缩小嫌疑犯的范围。找到嫌疑犯后,看看是否可以在一个简短的示例脚本中复制它。您希望尽可能多地消除促成因素的可能性。

    如果您想变得非常有趣,可以编写自己的Perl调试器。没那么难。您有机会在中运行一些子程序 DB

        2
  •  -1
  •   Brad Gilbert    16 年前

    如果问题出在Perl代码中,您可能有一个指向自身的引用,或者一个父节点。

    {
      my @a;
      @a = [\@a];
    }
    

    { package parent;
      sub new{ bless { 'name' => $_[1] }, $_[0] }
      sub add_child{
        my($self,$child_name) = @_;
        my $child = child->new($child_name,$self);
        $self->{$child_name} = $child;   # saves a reference to the child
        return $child;
      }
    }
    { package child;
      sub new{
        my($class,$name,$parent) = @_;
        my $self = bless {
          'name' => $name,
          'parent' => $parent # saves a reference to the parent
        }, $class;
        return $self;
      }
    }
    {
      my $parent = parent->new('Dad');
      my $child  = parent->add_child('Son');
    
      # At this point both of these are true
      # $parent->{Son}{parent} == $parent
      # $child->{parent}{Son}  == $child
    
      # Both of the objects **would** be destroyed upon leaving
      # the current scope, except that the object is self-referential
    }
    
    # Both objects still exist here, but there is no way to access either of them.
    

    解决此问题的最佳方法是使用 Scalar::Util::weaken .

    use Scalar::Util qw'weaken';
    { package child;
      sub new{
        my($class,$name,$parent) = @_;
        my $self = bless {
          'name' => $name,
          'parent' => $parent
        }, $class;
    
        weaken ${$self->{parent}};
    
        return $self;
      }
    }
    

        3
  •  -1
  •   macabail    16 年前

    您是如何写入数据库的?如果您正在使用任何DBI包或自定义包装器,请确保您正在刷新任何可以刷新的缓存对象或缓存变量。这些类型的内存膨胀问题比较常见,通常代表某个地方的共享对象缓存继续存在。

    尝试的事项:

    希望这能帮助一些人。

    推荐文章