2016-05-09 18 views
0

私は、何百年ものバックアップで何百ものテーブルを実行し、人々が求めるコンテンツを変更するスクリプトを持っています。perlプロセスの途中でスクリプトからRAMを解放する

今月の時点では、サーバがそれを殺すほどのRAMを使い始めました。

私はそれをプルした後、データを実行してデータを検索し、情報を検索して、それが次のものを引っ張る前に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); 
     } 

私は、行われたものを見ることができるように、私はデバッグコードを残しました失敗の場合。

+0

Perlには自動ガベージコレクタがあります。使用しているコードを表示することは賢明です。 – stevieb

+0

私はコードでそれを更新しました。 – Rich

+0

どの部分がほとんどのメモリを使いますか、ご存じですか?私はもう1つの可能性を持って自分の投稿を更新しました(あなたが投稿したコードを見るだけです)。 – zdim

答えて

0

あなたのプログラムがどのように編成されているかを知らなくても、本当に難しいです。

私は、データベースから適切なデータ構造にデータを読み込むことにします。また、処理を続けると、新しいデータを新しいデータ構造に読み込むことも想像しています。その記憶はすべて保持されており、私はそれを取り除く方法を知らない。私はあなたができないと思う。私が知る限り、Perlは実行時にOSにメモリを返さない。プログラムのメモリ使用量を増やさないようにするためのオプションがいくつかあります。

  • 最初に行うべきことは、データ構造を再利用することです。 1セットのデータの処理が完了したら、新しいアレイを同じ配列またはハッシュ(または使用するもの)に読み込みます。複雑なデータ構造を使用している場合は、それらのコンポーネントを再利用することができます。

  • あなたの質問から、この変更が多すぎるようです。そうであれば、私が考えることのできるもう一つのことは、コードの適切なセクションをサブシステムにラップすることです。処理が完了すると、そのコードは範囲外になり、そのメモリが解放されます。メモリはインタプリタに残っていますが、そのような作成されたサブのために再利用できるため、フットプリントが大きくならないことに注意してください。そのような変化はより実現可能性があります。

  • あなたのニーズがますます増しているのは、ほんの少しのデータがいくつかのデータ構造に入っているという単純な事実のためです。一度にデータのチャンクのみを読み込み(フェッチ、クエリ)し、処理が完了すると、次のチャンクを同じ配列に読み込みます。これは、データベースの読み込みパフォーマンスに影響する場合もありますが、メモリが減少する場合がありますプログラムのフットプリント。


アップデート(コードが掲載)  私はまだ、ほとんどのメモリがどこに行くか伝えることができませんが、おそらく以下が合理的であるかもしれません。この増加は、データが大きくなるにつれて、いくつかのデータ構造(配列?)が大きくなったり大きくなったりするためです。その場合、上記の最後のオプションが適切かもしれません。

1

問題はここではっきりと分かりません。明らかなメモリリークがあるようには見えないので、割り当てられたメモリを解放しようとすると、解決しなければならない問題ではないかもしれません。 Perlは理論的には実行中にOSにメモリを解放することができますが、特定の条件が満たされなければならず、私の経験では一般的な出来事ではありません。

dbに接続した後に$dbh->{mysql_use_result} = 1;を設定すると、大幅に役立ちます。

これは、DBI(実際にはlibmysqlclient)がソケットから着信データを読み取る方法を変更し、fetchrow*メソッドを呼び出すたびに必要に応じてデータを読み込み、メモリにバッファリングするのではなく、既にメモリ内にあるものからの時間です。これはデフォルトの動作です。

DBD::mysqlこのライブラリは、メモリ使用量の大部分を担うエンティティである可能性がありますので、これは有効です。

+0

+1ここでmysql_use_resultに代わる方法は、DBIの['column_info'](https://metacpan.org/pod/DBI#column_info)または単純に' SELECT * FROM $ tbl WHERE 1 = 0'を使うことです。 OPが関心を持っていると思われるNAMEです。 – pilcrow

+1

@pilcrowありがとう、とにかく、それは私が見落としてしまった本当に良い点です...後のステートメントハンドルの結果は実際には反復されているようです。 (?!)うまくいけば、メモリ自体がリークすることはありませんが、メモリとサーバのリソースが無駄になり、行がまったく必要ないときにテーブル全体をメモリに読み込むことになります。私はあなたが本当の問題を見つけたと思っています。私の解決策は、おそらくまだ有効ですが、実際の問題を隠すだけです。 –

0

便利なことが1つありますが、SQL文"select * from $_k"は、列の名前をフェッチするためにのみ実行されます。データが取り出されないように、それを"select * from $_k LIMIT 0"に変更することができます。非常に小さな違いを生むだろう場所に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; 

のように見える私はあなたかどうかわからないが、あなたはまた、」、forループの前にアップ$sth2->finishを移動する必要がありますあなたがをファイルまたはパッケージ変数の先頭に宣言した変数(ourで宣言されているか、またはuse strict 'vars'がない場合は宣言されていない)を使用している可能性が最も高い。練習)。そのようにして、すべての変数は一時的になりますそれが宣言されているブロックの最後で破壊されます。フルプログラムを見ずにはるかに多くのことを言うのは難しい

関連する問題