0

Webスクレイパーを開発しました。Web スクレーパーは 6 つのスレッドを使用し、各スレッドは Web ページを開き、記事のテキストを取得し、(ドライバーを使用して) mysql データベースにテキストの各単語を書き込みます。

プログラムの実行中に、Java mysql java.lang.OutOfMemoryError: Java heap space が発生します。Eclipse に Memory Analyzer をインストールしたところ、問題の原因は mysql ドライバー接続であることがわかりました。このプログラムを実行すると、5 分後にドライバーが占有する RAM は 6 MB、さらに 5 分後には 200MB、さらに 5 分後には 500Mb になり、次に、Java エラー ヒープ領域を取得します。

なぜこれが起こるのかわかりません。

モデルに使用するコードは次のとおりです(mysql DBにアクセスするため)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class model {

    private Connection connect = null;

    public model(){
         try {

              Class.forName("com.mysql.jdbc.Driver");
              connect = DriverManager.getConnection("jdbc:mysql://localhost/system?user=keyword_tool&password=l0gripp0");

            } catch (Exception e) {
                System.out.println(e);
            }
    }

    public synchronized void insertCat(String parola, String categoria){

        try{
            PreparedStatement statement = connect.prepareStatement("insert into sostantivi (nome, categoria) values (?, ?)");
            statement.setString(1, parola);
            statement.setString(2, categoria);

            statement.executeUpdate();
            statement.close();

        } catch (Exception e){
            //System.out.println(e);
        }

    }

    public void closeDBConnection() {
        try {
            connect.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

各スレッドは単にメソッド insertCat を呼び出し、データベースにカテゴリを持つ単語を挿入します。

Eclipse の Memory Analyzer プラグインには次のように書かれています。

ここに画像の説明を入力

ここに画像の説明を入力

4

3 に答える 3

2

あなたのコメントによると、「モデル」を 1 つだけ作成し (これは不適切なクラス名です)、6 つのスレッドで使用します。

これは特に優れた設計ではありません。単一の DB 接続 (スレッドごとに 1 つを使用できる場合) で同期することによってパフォーマンスが制限されるか、潜在的な同時実行の問題/エラーが発生します。

com.mysql.jdbc.JDBC4Connectionあなたのヒープダンプには1つしかありません。

これは、誤解を招く表示が原因である可能性があります。または(主張されている「単一モデル」アプローチにどの理論が適合するか)、PreparedStatements などですべてがいっぱいになっている可能性があります。

理論的には、これらはキャッシュして再利用する必要がありますが、実際には問題があります。次の 3 つの手順を試してください。

  1. MySQL ドライバーのバージョンを更新します。
  2. 約 1000 ステートメントごとに接続を閉じてから再度開きます。
  3. 各スレッドに独自の接続を与えるか、接続プールを使用します。

これは、Prepared Statement キャッシュに何らかの問題があるようです。コードで PreparedStmt または ResultSet の処理に関する他のバグを見つけられない限り (その可能性は明らかではありません)、1) と 2) が解決策または特定の回避策を提供する可能性が最も高くなります。

于 2013-08-27T09:20:53.493 に答える
0

破棄せずに新しいモデルを作成すると、新しい接続が作成され、マップには 2000000 個のモデルがあるため、2000000 個の接続が作成されます。

すべての接続コードを接続マネージャー プールに抽出し、自分で接続を管理する必要があります。

于 2013-08-27T09:17:25.307 に答える
0

このコードは、データベースへの接続を閉じません。

insertCatメソッドで接続を作成/閉じてみてください。接続は、できるだけ迅速に取得および解放する必要があります。接続は、永続化操作を実行するために必要な時間だけ開いておく必要があります。

public class model {

    public synchronized void insertCat(String parola, String categoria){
        Connection connect = null;
        try{
            Class.forName("com.mysql.jdbc.Driver");
            connect = DriverManager.getConnection("jdbc:mysql://localhost/system?user=keyword_tool&password=l0gripp0");
            PreparedStatement statement = connect.prepareStatement("insert into sostantivi (nome, categoria) values (?, ?)");
            statement.setString(1, parola);
            statement.setString(2, categoria);

            statement.executeUpdate();
            statement.close();

        } catch (Exception e){
            //System.out.println(e);
        }finally{
           if(connect != null){
               try {
                  connect.close();
               } catch (Exception e) {
                  System.out.println(e);
               }
           }
        }

    }

}
于 2013-08-27T09:12:57.117 に答える