1

巡回セールスマンの問題を解決するために、シミュレーテッド アニーリング アルゴリズムのこのコードを使用しています。都市の数は比較的少なく、約 30 ~ 40 です。問題は、1000 回目の繰り返しで OutOfMemory エラー メッセージ (INSIDE THE FUNCTION "GO") が表示されることです。なぜこれが起こるのですか?この問題にどう取り組むか?

package tsptw.logic;

import java.util.ArrayList;
import java.util.Random;

import tsptw.logic.objects.Point;
import tsptw.logic.objects.Solution;

public class SimulatedAnnealing {

    private static final double COOLING_ALPHA = 0.95;
    private static Random rand = new Random();
    private static int i = 0;

    public static Solution solve(Point start, ArrayList<Point> points) {
        Solution sol = Solution.randomSolution(start, points);
        double t = initialTemperature(sol, 1000);
        int frozen = 0;
        System.out.println("-- Simulated annealing started with initial temperature " +
                t + " --");
        return go(sol, t, frozen);
    }

    private static Solution go(Solution solution, double t, int frozen) {
        if (frozen >= 3) {
            return solution;
        }
        i++;

        Solution bestSol = solution;
        System.out.println(i + ": " + solution.fitness() + " " + solution.time() + " "
                + solution.penalty() + " " + t);
        ArrayList<Solution> nHood = solution.nHood();

        int attempts = 0;
        int accepted = 0;

        while (!(attempts == 2 * nHood.size() || accepted == nHood.size())) {
            Solution sol = nHood.get(rand.nextInt(nHood.size()));
            attempts++;

            double deltaF = sol.fitness() - bestSol.fitness();
            if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
                accepted++;
                bestSol = sol;
                nHood = sol.nHood();
            }
        }

        frozen = accepted == 0 ? frozen + 1 : 0;

        double newT = coolingSchedule(t);
        return go(bestSol, newT, frozen);
    }

    private static double initialTemperature(Solution solution, double t) {
        ArrayList<Solution> nHood = solution.nHood();
        int accepted = 0;
        int attempts = nHood.size();
        for (Solution sol : nHood) {
            double deltaF = sol.fitness() - solution.fitness();
            if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
                accepted++;
            }
        }
        double r = ((double)accepted) / attempts;

        if (r >= 0.94 && r <= 0.96) {
            return t;
        }
        return initialTemperature(solution, r > 0.95 ? t/2 : 2*t);
    }

    private static double coolingSchedule(double t) {
        return COOLING_ALPHA * t;
    }
}
4

6 に答える 6

1

再帰が大きなヒープを生成しているようです。コードが正しく、再帰を保持したい場合は、少しクリーンアップしてみてください。私の最初の候補はnHood.clear(). プロファイラーを使用してメモリ イーターを特定します。

VM のヒープ サイズを増やすことは、最後の手段です。再帰をループにリファクタリングすることをお勧めします。

于 2014-01-07T15:40:28.827 に答える
1

JVM のヒープ サイズを大きくする以外に、(関数に何度もアクセスする場合は、おそらくかなり) 役立つことの 1 つは、 などの変数の作成を関数自体の外に移動するnHoodことですsolbestSol. 関数に入るたびに新しいオブジェクトを作成すると、以前に作成したオブジェクトに新しい値を割り当てるよりも多くの時間とスペースが必要になります。再帰関数では、多くの場合、最後の関数呼び出しに到達する前の中間ステップで作成されたすべての変数がメモリに保持されるため、変数attemptsacceptedクラス変数を作成し、新しい変数を作成する代わりにその場所で値を再設定するだけです。もの、役立ちます。

于 2014-01-07T15:40:33.573 に答える
0

複雑なアルゴリズムを実行するときによくある問題です。これを参照して、ヒープ メモリ サイズを増やしてみてください: Eclipse での Java ヒープ サイズの増加 - 仮想メモリの使用

于 2014-01-07T15:33:44.430 に答える
0

Eclipse で、プログラムの実行構成に移動します。

[実行] > [RunConfiguration...] > [引数] > [VM 引数:] に続いて、次の行を入力します。

-Xmx500m

これにより、最大 500M のメモリを許可するように仮想マシンが構成されます。うまくいけば、それで十分です

PS - その数の都市では、各都市の大量のデータを扱っていない限り、この問題は発生しません。

于 2014-01-07T15:35:00.117 に答える
0

最大ヒープサイズを増やそうとしましたか? 一部の環境では、デフォルトでかなり制限されています (Matlab)。

パラメータ -Xmx4g を使用して、制限を 4GB のヒープ メモリに設定できます。

Java でヒープ サイズを増やす http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html

于 2014-01-07T15:37:30.657 に答える