【问题标题】:How to explicitly free memory that was used by native code in Java/Android如何显式释放 Java/Android 中本机代码使用的内存
【发布时间】:2018-02-13 17:10:13
【问题描述】:

我在我的 Android 项目中使用 DL4J 来运行 CNN 网络作为分类器。问题是这个 CNN 模型占用的内存超过了我的智能手机允许的每个应用程序堆大小,这导致内存不足错误。所以,我想知道是否有办法显式释放这个原生 DL4J 代码分配的内存。

我的输入总共是 200 个图像补丁。我需要将它们堆叠在一起,以便处理时间更快。我尝试将批量大小设置为 32,因此每个输入 INDARRAY 的大小为 [32、3、44、44]。我也尝试了 16、8 等。但唯一没有出现内存不足错误的情况是我一次输入一个图像补丁。但我无法承受它导致的长处理时间。

我尝试使用 GC 显式释放内存,但没有成功,这是有道理的,因为内存已被本机代码占用。

for (int i = 0; i < N / UtilsCustom.NN_batch_size; i++) {
                                INDArray temp = UtilsCustom.overallArray.get(NDArrayIndex.interval(i * UtilsCustom.NN_batch_size, i * UtilsCustom.NN_batch_size + UtilsCustom.NN_batch_size), NDArrayIndex.all(), NDArrayIndex.all(), NDArrayIndex.all());
                                NN_classify(temp);
                                a = i * UtilsCustom.NN_batch_size + UtilsCustom.NN_batch_size;

                                if (i%2==1){
                                    model = null;
                                    java.lang.System.gc();
                                    Log.d(TAG, "GCGCGC");
                                    try {
                                        Thread.sleep(1000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }

                                    loadNNModel();
                                }

                                temp = null;
                                java.lang.System.gc();
                            }

private void NN_classify(INDArray imageMat) {

        int result;

        DataNormalization scaler = new ImagePreProcessingScaler(0, 1);
        scaler.transform(imageMat);

        INDArray output = model.output(imageMat);

        Log.d(LOG_TAG, "output.size(): " + output.size(0) + ", " + output.size(1));

        double prob_parasitemic = 0, prob_uninfected = 0;

        for (int i = 0; i < output.size(0); i++) {
            prob_parasitemic = output.getDouble(i, 0);
            prob_uninfected = output.getDouble(i, 1);
            Log.d(LOG_TAG, "prob_parasitemic: " + i + " " + output.getDouble(0, 0));
            Log.d(LOG_TAG, "prob_uninfected: " + i + " " + output.getDouble(0, 1));
        }

        if (prob_parasitemic > prob_uninfected) {
            result = 2;
        } else {
            result = 1;
        }

        Log.e(LOG_TAG, "Result: " + result);

        imageMat = null;
        output = null;
        java.lang.System.gc();
    }

【问题讨论】:

  • 也许应该将训练数据发送到服务(可以缩放),并将学习模型返回到设备。

标签: java android dl4j


【解决方案1】:

java.lang.System.gc() 并没有按照你的想法去做。它不像 C 中的 free 或 C++ 中的 delete。

更多的是对 JVM 运行垃圾回收的“建议”。它不会强制进行垃圾收集或释放内存。

参考:https://stackoverflow.com/a/66573/9241296

它说,

我不会在您的代码中依赖它。如果 JVM 即将抛出 OutOfMemoryError,调用 System.gc() 不会阻止它,因为垃圾收集器会在它达到那个极端之前尝试尽可能多地释放。

【讨论】:

  • 实际上,它可能只需要那么多内存。尝试将批次设置为 1 项,看看它使用了多少内存。如果它正在使用 X 内存并且您没有足够的内存来进行 2X,那么您无法在逻辑上将另一个项目放入批处理中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
  • 2019-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多