【问题标题】:OutOfMemory issue with simulated annealing code模拟退火代码的 OutOfMemory 问题
【发布时间】:2014-01-07 15:30:08
【问题描述】:

我正在使用模拟退火算法的this code 来解决旅行商问题。城市数量相对较少,即 30-40 个左右。问题是在第 1000 次迭代时,我收到 OutOfMemory 错误消息(在函数“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;
    }
}

【问题讨论】:

  • JVM 参数?您是否进行了堆转储并对其进行了分析?

标签: java eclipse out-of-memory simulated-annealing


【解决方案1】:

除了增加 JVM 的堆大小之外,还有一件事会有所帮助(当您多次进入函数时,可能会有所帮助)是移出变量的创建,例如 nHoodsolbestSol 在函数本身之外。每次进入函数时创建新对象比为以前创建的对象分配新值需要更多的时间和空间。使用递归函数,在到达最终函数调用之前,通常在中间步骤中创建的所有变量都将保存在内存中,因此即使将变量 attemptsaccepted 设置为类变量,然后重新设置它们的值地方,而不是创建新的地方,会有所帮助。

【讨论】:

    【解决方案2】:

    看起来递归正在产生一个大堆。如果您的代码是正确的并且您想保持递归,您可能会尝试清理一下。我的第一个候选人是nHood.clear()。使用分析器来识别你的记忆吞噬者。

    增加虚拟机的堆大小应该是最后的手段。我宁愿建议将递归重构为循环。

    【讨论】:

      【解决方案3】:

      这看起来很糟糕:

      ArrayList<Solution> nHood = solution.nHood();
      // How many solutions do you have in memory?
      // How much memory does 1 solution take?
      

      在实施模拟退火时,还要查看 just in time random selection。尤其是当每个社区的移动次数激增(随着您的城市数量增加)时,这也可以防止您的记忆也爆炸。

      【讨论】:

        【解决方案4】:

        当您运行复杂的算法时,这是一个常见的问题。尝试增加堆内存大小见:Increasing Java heap size in Eclipse - using virtual memory

        【讨论】:

          【解决方案5】:

          在 Eclipse 中,转到您的程序的运行配置:

          运行 > RunConfiguration... > 参数 > VM 参数:然后键入以下行:

          -Xmx500m

          这会将虚拟机配置为允许最多 500M 的内存。希望那将是 够了

          附: - 对于这么多城市,除非您处理每个城市的大量数据,否则您应该不会遇到此问题。

          【讨论】:

          • 可能发生这种情况是因为我针对不同的城市集多次执行算法。
          【解决方案6】:

          您是否尝试增加最大堆大小? 一些环境默认设置它非常有限(Matlab)。

          您可以使用参数 -Xmx4g 将限制设置为 4GB 的堆内存。

          Increase heap size in Java http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/jrdocs/refman/optionX.html

          【讨论】:

            猜你喜欢
            • 2023-04-02
            • 2013-06-21
            • 2011-01-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多