Java GC没有收集某些Object

时间:2013-10-14 12:19:01

标签: java garbage-collection

我的应用程序存在问题,并将其缩小了一点。似乎我的记忆中有未使用的物体。

但奇怪的是,GC不会收集它们(即使不是程序基本上是空闲的,即没有处理线程处于活动状态),但是当我在Netbeans IDE的Profiler中按“收集垃圾”时,它会收集。

我发现了负责临时使用大量内存的代码:

private Integer getWhiteLines(BufferedImage image) {
    Map<Integer, List<Color>> heightColors = new HashMap<>();

    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }
        heightColors.put(h, colors);
    }

    Integer whiteLines = 0;
    for (Map.Entry<Integer, List<Color>> entry : heightColors.entrySet()) {
        Color avgColor = avgColor(entry.getValue());
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }
    return whiteLines;
}

它列出了图像中每个像素的颜色(以前是PDF文件)。

这个问题也很大,例如在某些PDF上,Color对象占用了14MB的内存。

为什么会出现这种情况?我将如何解决这个问题?

3 个答案:

答案 0 :(得分:1)

只有当您需要内存分配并且您的VM没有足够的资源时,才会强制GC收集内存。您可以通过这种方式减少占地面积:

private Integer getWhiteLines(BufferedImage image) {
    Integer whiteLines = 0;
    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }

        Color avgColor = avgColor(colors);
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }

    return whiteLines;
}

答案 1 :(得分:1)

没有明显的理由让您将每行的colors ArrayList保存到Map中,然后单独迭代以计算平均颜色并确定它是否为白线。你可以在一个循环中完成所有这些:

private Integer getWhiteLines(BufferedImage image) {
    Integer whiteLines = 0;
    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }
        Color avgColor = avgColor(colors);
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }
    return whiteLines;
}

这将导致对象超出范围(因为Color对象仅为外循环的每次迭代保留,而不是为函数的整个执行时间保留),并且该内存为可用于早期的垃圾收集。

但是,值得注意的是,垃圾收集器不一定会在程序空闲时运行。它不是一个免费的进程,因此只有在实际需要释放内存时才会发生垃圾收集。符合垃圾收集条件的对象并不意味着它的内存将立即被回收。

答案 2 :(得分:0)

当应用程序空闲时,您无法说出何时会收集垃圾内存。你有过默认的例外吗?此外,如果应用程序占用大量内存,您可以使用-Xms -Xmx JVM参数限制它。

对于此类任务,您应该考虑在迭代输入值时计算值。

如果你不能在飞行中做,你应该考虑重新使用第一次创建的对象。