Java:即使代码正确,递归也会导致堆栈溢出错误

标签 java recursion memory-management stack stack-overflow

我正在尝试制作一个程序来遍历 Sprite 图像,然后将其中的每个形状变成一个新图像。例如,如果我们选择马里奥,我希望帽子是一个图像,脸是另一个图像,依此类推。我已经让我的程序可以在小型 32x32 图像上运行,但如果我想在较大图像上运行它,则会导致堆栈溢出错误。如果我使用 C++,我会在每次递归调用后清除堆栈来解决此问题,但据我所知,Java 不允许您直接清除堆栈。我希望我的程序能够在 Windows、Linux 和 Mac 上运行,所以我认为 Java 将是最好的选择,所以我真的不想切换我正在使用的语言。有没有办法在 Java 中每次递归调用后删除存储在堆栈上的内容? 这是我的代码,以防万一出现错误。

 private void makeShape(int x, int y)
    {
        if(x < 0 || y < 0 || y >= sprite.getHeight() || x >= sprite.getWidth())
        {
            return;
        }
        if(sample == colorData[y][x] && table[y][x])
        {
            tempBlankImage[y][x] = sample;
            table[y][x] = false;
            makeShape(x, y - 1);
            makeShape(x, y + 1);
            makeShape(x - 1, y);
            makeShape(x + 1, y);
        }
        else
        {
            return;
        }

    }

x 和 y 点是通过 for 循环生成的,该循环遍历图像并检查点是否已添加到形状中,如果没有,则根据其周围的像素创建形状。

更新:

    private int[][] makeShape(int sample, int x, int y)
    {
        int[][] tempBlankImage = blankImage();
        Queue<Point> queue = new LinkedList<Point>();
        queue.add(new Point(x,y));
        while(!queue.isEmpty())
        {
            Point point = queue.remove();
            if(sample == colorData[point.y][point.x] && table[point.y][point.x])
            {
                tempBlankImage[point.y][point.x] = sample;
                table[point.y][point.x] = false;
                if(point.y < sprite.getHeight() -1)
                    queue.add(new Point(point.x, point.y+1));
                if(point.y > 0)
                    queue.add(new Point(point.x, point.y-1));
                if(point.x < sprite.getWidth()-1)
                    queue.add(new Point(point.x+1, point.y));
                if(point.x > 0)
                    queue.add(new Point(point.x-1, point.y));
            }

        }
        queue = null;
        return tempBlankImage;
    }

堆栈溢出错误已停止,现在我出现内存不足:Java 堆空间,即使我将其增加到 2 GB。我将每个 int[][] 添加到 ArrayList 中,我猜这就是问题所在。我还能如何存储数据?

最佳答案

Java 以其自动定义良好且经过测试的内存管理系统而闻名 - 即使可能,自行管理内存通常也不是一个好主意(因为在某种程度上,它实际上是)。

如果算法执行时间能让你长出 mustache 并能够给你的孙子们讲关于它的故事,那么清理堆栈会给你带来什么?

不要使其递归 - 考虑算法的某种迭代形式。例如,您可以迭代所有图像的像素并将它们添加到适当的图像(由于其颜色),该图像将存储在某些 HashMap 中,如以下伪代码

    HashMap<Color, Image> images= new HashMap<Color, Image>();

    for(Pixel pixel : originImage)
        Color color = pixel.getColor();
        images.get(color).put(pixel)

不要为糟糕的代码浪费生命

关于Java:即使代码正确,递归也会导致堆栈溢出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34325630/

相关文章:

java - 你如何从 Java 中的 InputStream 读取并转换为字节数组?

java - JUnit4 - 'same' 测试用例的不同超时

java - JSF 中的 PropertyNotWritableException,即使属性是可写的

java - 生成数独网格时出现意外输出

python - 内存映射文件如何处理大于内存的文件?

java - 递归二分查找和排序

c++ - 递归快速排序导致段错误(不是溢出)

optimization - Common Lisp 中的高效收集函数

php - 如何在 PHP 中为数组预分配内存?

c - C程序内存泄漏,看不到在哪里释放内存