我的应用程序存在问题,并将其缩小了一点。似乎我的记忆中有未使用的物体。
但奇怪的是,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的内存。
为什么会出现这种情况?我将如何解决这个问题?
答案 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参数限制它。
对于此类任务,您应该考虑在迭代输入值时计算值。
如果你不能在飞行中做,你应该考虑重新使用第一次创建的对象。