首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >"outOfMemoryError java堆空间“计算直方图,内存与时间的交易?

"outOfMemoryError java堆空间“计算直方图,内存与时间的交易?
EN

Stack Overflow用户
提问于 2016-11-14 22:25:54
回答 2查看 199关注 0票数 1

我已经用我的项目工作了一段时间,它在某些时候计算一个大图像的直方图(处理高达40 my的照片,但一般在10-20 my左右。)

我总是使用一台16 of内存的笔记本电脑,我没有注意到任何问题。今天,我换了一台6GB的内存笔记本电脑,在计算直方图时,我看到了17 was的照片,这个异常开始出现。

我用这种方法计算它,因为它比迭代所有像素和获取每个像素中的所有颜色更快。

你对我该如何写这样的代码有什么建议?

如果我希望使程序更快,我认为我需要使用更多的内存(这个大的double[]对象)。如果PC有足够的RAM,就不会有任何问题,程序也会顺利运行,但是如果PC没有这么多RAM,它就会崩溃,使程序变得无用。

那么,我是否应该通过手工迭代所有像素,以“较慢的方式”编写代码,并使其“更安全”呢?

还是我做错了什么,同时做了这两件事?

这是发生此outOfMemoryError时的代码段:

代码语言:javascript
复制
// dataset
    dataset = new HistogramDataset();
    final int w = image.getWidth();
    final int h = image.getHeight();
    double[] r = new double[w * h]; //Here some PC's with not enough RAM will crash
    double[] s = new double[w * h];
    double[] t;
    r = raster.getSamples(0, 0, w, h, 0, r);
    s = r;
    dataset.addSeries(lang.getString("HistogramRGB.String.red"), r, BINS);
    r = raster.getSamples(0, 0, w, h, 1, r);
    t = new double[r.length + s.length]; //Add R+G
    System.arraycopy(s, 0, t, 0, s.length);
    System.arraycopy(r, 0, t, s.length, r.length);
    dataset.addSeries(lang.getString("HistogramRGB.String.green"), r, BINS);
    r = raster.getSamples(0, 0, w, h, 2, r);
    s = new double[r.length + t.length]; //Add R+G+B
    System.arraycopy(t, 0, s, 0, t.length);
    System.arraycopy(r, 0, s, t.length, r.length);
    dataset.addSeries(lang.getString("HistogramRGB.String.blue"), r, BINS);
    dataset.addSeries(lang.getString("HistogramRGB.String.brigthness"), s, BINS);

    // chart
    chart = ChartFactory.createHistogram(lang.getString("HistogramRGB.String.histogram"), "",
            "", dataset, PlotOrientation.VERTICAL, false, true, false);

Update:使用注释中建议的选项-Xmx解决问题。

结果使用@TheConstructor优化,在使用windows 10 32位和3,5GB ram的虚拟机中:

  • 在使用小于-Xmx1444m的优化之前,将运行异常
  • 使用小于-Xmx824m的优化之后,将运行异常

默认情况下,这就是我所拥有的:

代码语言:javascript
复制
java -XX:+PrintFlagsFinal -version | findstr HeapSize
uintx ErgoHeapSizeLimit                         = 0                                   {product}
uintx HeapSizePerGCThread                       = 67108864                            {product}
uintx InitialHeapSize                          := 16777216                            {product}
uintx LargePageHeapSizeThreshold                = 134217728                           {product}
uintx MaxHeapSize                              := 268435456                           {product}
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) Client VM (build 25.111-b14, mixed mode, sharing)

它大约为268 by,这台计算机中的命令所能设置的最大容量是1,5GB。我觉得奇怪的是,没有其他任何东西,用任何其他程序打开整个窗口都需要3.5GB中的2GB。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-14 23:44:42

最终,我想您需要为您的-Xmx -call指定一个大小正确的java或-call参数。缺省值是从可用内存中派生的,并限制了Java可以使用的内存量。试着找出一个可行的尺寸。你可以试试,例如-Xmx2g。关于-Xmx 可以在文档中找到的一些细节

查看您的代码,您可以消除t并跳过s的初始化。虽然我想这并不能解决所有的问题,但这里是我的修改:

代码语言:javascript
复制
    // dataset
    dataset = new HistogramDataset();
    final int w = image.getWidth();
    final int h = image.getHeight();
    double[] buffer = new double[w * h];
    double[] rgb;

    buffer = raster.getSamples(0, 0, w, h, 0, buffer);
    rgb = Arrays.copyOf(buffer, buffer.length * 3); // copy as otherwise it gets overwritten in next getSamples
    dataset.addSeries(lang.getString("HistogramRGB.String.red"), buffer, BINS);

    buffer = raster.getSamples(0, 0, w, h, 1, buffer);
    System.arraycopy(buffer, 0, rgb, buffer.length, buffer.length); //Add G
    dataset.addSeries(lang.getString("HistogramRGB.String.green"), buffer, BINS);

    buffer = raster.getSamples(0, 0, w, h, 2, buffer);
    System.arraycopy(buffer, 0, rgb, buffer.length * 2, buffer.length); //Add B
    dataset.addSeries(lang.getString("HistogramRGB.String.blue"), buffer, BINS);

    dataset.addSeries(lang.getString("HistogramRGB.String.brigthness"), rgb, BINS);

    // chart
    chart = ChartFactory.createHistogram(lang.getString("HistogramRGB.String.histogram"), "", "", dataset,
            PlotOrientation.VERTICAL, false, true, false);

根据addSeries是否创建所提供数据的副本,您可能需要在每次调用getSamples之前为buffer分配一个新数组。如果我正确地猜到它是Raster#getSamples,您也可以使用(double[]) null作为参数,而不是buffer,让getSamples为您分配数组。

如果精度不太重要,您也可以用float[]切换float[],这节省了一半的内存。

票数 3
EN

Stack Overflow用户

发布于 2016-11-15 08:06:12

如果可能,最好减少对象的创建,这样堆空间内存就会减少。如果应用程序中所有对象都是必需的,那么在运行应用程序时使用命令行参数:

代码语言:javascript
复制
java -Xms<size>        set initial Java heap size 

(OR)

java -Xmx<size>        set maximum Java heap size
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40598870

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档