【问题标题】:fractals and "java.lang.OutOfMemoryError: Java heap space"分形和“java.lang.OutOfMemoryError:Java 堆空间”
【发布时间】:2012-02-01 20:16:16
【问题描述】:

我在java中做Koch fractal snowflake并将它保存在一个svg文件中。

我正在使用 LineStrip2D 类来记忆分形(它是实现可迭代的 Vec2D 的 ArrayList 的包装器)。

主要功能是这个:

public static LineStrip2D repeatPatternIntoLineStrip2D(
        LineStrip2D pattern,
        LineStrip2D polygon, 
        boolean repeatUp) {

    /*
     * pattern: must be a pattern between Vec(0,0) and Vec(1,0)
     *          (normalized beetween 0-1 and in X axis)
     * */

    float angle, distance;
    Vec2D pivot, a, b, direction, b1;
    LineStrip2D new_polygon = new LineStrip2D();

    new_polygon.add(pattern.vertices.get(0));
    a = polygon.vertices.get(0);

    int count=0;
    for (int i = 1; i < polygon.vertices.size(); i++) {
        b = polygon.vertices.get(i);
        a = polygon.vertices.get(i-1);

        distance = b.distanceTo(a);
        direction = b.sub(a).normalize();
        angle = PApplet.atan2(direction.y, direction.x);
        pivot = a;

        for (int j = 1; j < pattern.vertices.size(); j++) {
            Vec2D _b1 = pattern.vertices.get(j);

            b1 =  _b1.copy() ;

            if(repeatUp)b1.y *= -1;             
            b1.scaleSelf(distance);
            b1 = b1.rotate(angle);
            b1.addSelf(pivot);

            new_polygon.add(b1);
            count++;
        }
        a = b;
    }
    System.out.println(count);
    return new_polygon;
}

我有一个带有初始科赫曲线的模式:

我打电话给:

pattern = GeometryHelper.repeatPatternIntoLineStrip2D(pattern, pattern, false);

现在的问题:

经过一些迭代 (851968) 我有一个 java.lang.OutOfMemoryError: Java heap space。 如何避免此错误并获得巨大的 svg 文件? 我想我可以通过不同的步骤来完成这个过程,但我不明白如何以一种聪明的方式实现它。

【问题讨论】:

    标签: java out-of-memory heap-memory fractals


    【解决方案1】:

    首先你为什么使用变量count?您可以用System.out.println(polygon.vertices.size() * polygon.vertices.size()); 替换它,并无缘无故地删除增加count 的无用操作。

    对于内存不足错误,请尝试增加 VM 的堆大小

    【讨论】:

    • 我怀疑消除一个变量会解决他的堆大小问题。
    • 我只是指他的代码中有一些无用的操作
    • @Jason482:+1 抵消 -1:答案是正确的,包含可能有用的附加信息,实际上是 第一个 正确答案(尽管带有比另一个少一点细节)。恕我直言,不值得投反对票。
    • 感谢您的反对,但您能解释一下原因吗? (无论你是谁)
    • @AdelBoutros:您是删除了以前的 cmets,还是版主删除了?
    【解决方案2】:

    首先也是最简单的方法是给 JVM 更多内存。添加 -Xmx=1g 可能就足够了(并且现在可以在大多数机器上使用)。如果您需要更多,请随意添加,直到超出您机器的可用容量为止。

    话虽如此,处理分形总会有一个内存使用上限。首先,您应该分析您的应用程序以查看所有内存都在哪里使用。一旦你发现了这一点,你就可以考虑重新解决这个问题,以便对内存更加友好。或者,您可以转向在迭代之间进行迭代并将结果保存到磁盘的设计,以节省先前迭代的内存。

    【讨论】:

      【解决方案3】:

      正如其他人所提到的,第一步是尝试通过修改JVM堆大小(它是命令行参数 -Xmx=... where ...是您希望分配的最大内存大小)。如果您的机器上有足够的 RAM,那么您可以将其设置得相当高(也许有一种方法可以让 JVM 使用磁盘交换空间,所以它可能非常高,但我不知道如何/如果这是可能的)。

      如果这还不够,那么您将需要管理您自己在迭代(非递归)实现中使用的堆栈并将其序列化到磁盘。这看起来是您将堆栈作为参数传递给您的函数,并且该函数将从堆栈中读取其参数(将它们留在堆栈上),然后在循环之前将参数写入堆栈(和当你达到你想要的最大深度时,你就开始从堆栈中弹出数据)。迭代实现和堆栈管理非常重要,堆栈的序列化/持久性也是如此(随着大小的增加,堆栈需要自行管理以将部分存储到磁盘)。

      【讨论】:

      • 我在哪里可以找到一些关于如何在堆栈上实现序列化的解释?
      • 我又参与了这个项目,这似乎是我可以实施的最佳解决方案。但我还没有完全理解..没有办法得到进一步的解释或例子?
      • @nkint 您现在将堆大小设置为多少?您的机器上有多少可用 RAM?
      【解决方案4】:

      我认为问题与封装 ArrayList 的 LineStrip2D 类有关:List 实现是由 Array 提供的后端,其大小线性增长(如此处所述ArrayList: how does the size increase?)。 我相信你的内存用完了,因为 ArrayList 分配了一个具有新大小的全新数组,同时保留了旧数组 (http://en.wikipedia.org/wiki/Dynamic_array)。因此,要完成您的绘图,您至少需要 2*MAX_SIZE。 您应该增加总堆,但切换到 LinkedList 应该会改善这种情况。

      【讨论】:

        猜你喜欢
        • 2012-09-28
        • 2010-12-08
        • 2015-05-14
        • 2019-07-10
        相关资源
        最近更新 更多