perl在进程中间从脚本释放RAM

时间:2016-05-09 00:15:53

标签: mysql perl ram

我有一个脚本,可以运行数年(如果不是数千个)来自多年备份的表,以更改人们要求的内容。

截至本月,它开始使用如此多的RAM,服务器将其杀死。

那么,每次从数据库中拉出后,有没有办法,在我拉出它并让我的perl脚本运行数据后,搜索要更改的信息,它会在拉出下一个之前重置RAM?

所以基本上它会重置它刚刚提取的数据,所以所有这些都不在RAM中?

我在2007年创造了这个东西,我当然希望我做得与众不同,但这需要进行大修和更新,而现在我无法做到这一点。或许在将来。但截至目前,我不能那样做。

所以我需要一种方法来防止这种情况发生。

如果你知道如何冲洗那段记忆,请告诉我。

如果你能指出我的话,请提前感谢你。

---更新----添加了部分实际提取所有数据的网站代码----

        $_startingTime = time();
        $dbh->do(qq{update `tun_changes` set `status` = "working", `startedT` = ? where `unid` = ?}, undef, $_startingTime, $_tr->{unid});
        $sth2 = $dbh->prepare(qq{select * from `allmembers` where `mId` = ?});
        $sth2->execute($_tr->{mId});
        $_tregmem = $sth2->fetchrow_hashref();
        $sth2->finish();
        $dbh->do(qq{delete from `sessions` where `id` = "$_tregmem->{last_sessid}"}); #kill their logged in session, so it does not lock them up if they are logged in when we change their username...
        $_un = $_tregmem->{tusername};
        $_cust_id = $_tr->{mId};
        $_notfinished = 0;
        $_newUname = lc($_tr->{newun});
        $_csusername = $_tr->{csusername};# if customer service rep...
        $_count = 0;
        $_changeFailed = 0;
        $_changed = 0;
        $_debugChg = 1;
        if($_debugChg) {
            open(DBG,">>/home$_website_username/required/files/urgent/all_chg_uname_debug_track.txt");
            seek(DBG,0,2);
            print DBG "Checking Table at " . Format_Date_For_Viewing($_startingTime,"") . " - indented two lines at least for this record.... until _end_ is shown\n";
        }
        @_mb = $dbh->tables;
        $_tablesAffected = 0;
        foreach $_k (@_mb) {
            $_sql = "select * from $_k";
            if($_debugChg) {
                print DBG "\tTable $_k (" . duration(time() - $_startingTime) . " into action)\n";
            }
            $sth2 = $dbh->prepare($_sql);
            $sth2->execute();
            @_mb2 = @{$sth2->{NAME}};
            foreach $_k2 (@_mb2) {
                if($_debugChg) {
                    print DBG "\t\tColumn $_k2";
                }
                if($_k2 =~ /tusername/i) {
                    if($_debugChg) {
                        print DBG "\t Checking for username entries in $_k2\n";
                    }
                    $_updated = $dbh->do(qq{update $_k SET `$_k2` = ? WHERE `$_k2` = ?}, undef, $_newUname, $_un);
                    if($_updated) {
                        $_changed += $_updated;
                    } else {
                        $_changeFailed += $_updated;
                    }
                } else {
                    if($_debugChg) {
                        print DBG " - Not UN\n";
                    }
                }
            }
            $sth2->finish();
            if($_debugChg) {
                print DBG "\n";
            }
        }
        if($_debugChg) {
            print DBG "\nFinished - Duration was: " . duration(time() - $_startingTime) . "\n";
            print DBG "\n_end_\n\n";
            close(DBG);
        }

我离开了调试代码,以便在出现故障时可以看到已完成的操作。

3 个答案:

答案 0 :(得分:1)

这里的问题不是很明显。看起来没有明显的内存泄漏,因此尝试释放已分配的内存可能不是您需要解决的问题。 Perl理论上可以在运行时将内存释放回操作系统,但是必须满足某些条件,根据我的经验,它并不常见。

连接到数据库后设置$dbh->{mysql_use_result} = 1;可能会有很大帮助。

这改变了DBI(实际上,libmysqlclient)从套接字读取传入数据的方式,导致它在每次调用fetchrow*方法时根据需要读取数据,而不是先将它全部缓冲到内存中,然后交给你从内存中已有的一行开始,这是默认行为。

DBD::mysql并且底层库可能是负责大量内存使用的实体,所以这值得一试。

答案 1 :(得分:0)

如果不知道至少有关程序的组织方式,那真的很难说。

我认为您将数据库中的数据读入合适的数据结构。我还想象一下,当您继续处理时,您会将新数据读入新的数据结构中。保留所有记忆,我不知道如何摆脱它。我想你不能;据我所知,Perl在运行时不会将内存返回给操作系统。以下是一些选项,可以防止程序的内存占用增长。

  • 要做的第一件事是重用数据结构。处理完一组数据后,将新数据读入相同的数组或散列(或任何使用的数据)。如果您使用复杂的数据结构,则可以重复使用它们的组件。

  • 从您的问题看来,这可能构成了太多的变化。如果是这样的话,我可以想到的另一件事是将代码的适当部分包装到subs中,这样一旦完成处理,它就会超出范围并释放内存。请注意,内存仍将与解释器一起使用,但它可以重新用于下一个这样的组合子,因此您的足迹不会增长。这种改变可能更可行。

  • 如果你的内存需求增长是由于一些简单的事实,即只有更多的数据进入一些数据结构,这是另一个想法。一次只读取(获取,查询)一大块数据,然后当您完成处理时,将下一个块读入同一个数组等。这可能会也可能不会影响数据库读取性能,但会导致内存减少该计划的足迹。

更新(已发布代码)我仍然无法分辨大多数内存的去向,但以下内容可能是合理的。似乎增加的原因是一些数据结构(数组?)随着数据的增长而变得越来越大。在这种情况下,上面的最后一个选项可能是合适的。

答案 2 :(得分:0)

可能有用的一件事是,SQL语句"select * from $_k"仅用于获取列的名称。您可能希望将其更改为"select * from $_k LIMIT 0",以便不会检索任何数据。您还应该在$sth2->finish循环之前移动for,尽管LIMIT 0修复位置会产生很小的差异

结果代码如下所示

$_sql = "select * from `$_k` LIMIT 0";
if ( $_debugChg ) {
    print DBG "\tTable $_k (" . duration( time() - $_startingTime ) . " into action)\n";
}
$sth2 = $dbh->prepare($_sql);
$sth2->execute;
@_mb2 = @{ $sth2->{NAME} };
$sth2->finish;

我不知道你是使用在文件顶部或包变量中声明的my变量(用our声明,或者如果你没有{{1}则只是未声明可能值得在尽可能最严格的范围内用use strict 'vars'声明所有内容(这是标准的最佳实践)。这样每个变量都是临时的,并且会在块的末尾被销毁。如果没有看到完整的程序,很难说更多。