3

Android fails to allocate enough memory when I run application and want to load

java.lang.OutOfMemoryError: Failed to allocate a 202728962 byte allocation with 14422192 free bytes and 171MB until OOM

Also I previously described an error here: https://github.com/tensorflow/tensorflow/issues/9343

I guess I have enough free memory (usually 1.0-1.5 gb are free):

enter image description here

And so is it just java android limitation? Can I somehow solve it with java? Or is it possible only with NDK?

full error code:

04-21 09:40:52.731 31597-31597/org.tensorflow.demo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: org.tensorflow.demo, PID: 31597
    java.lang.OutOfMemoryError: Failed to allocate a 202728962 byte allocation with 14422192 free bytes and 171MB until OOM
        at org.tensorflow.contrib.android.TensorFlowInferenceInterface.loadGraph(TensorFlowInferenceInterface.java:377)
        at org.tensorflow.contrib.android.TensorFlowInferenceInterface.<init>(TensorFlowInferenceInterface.java:96)
        at org.tensorflow.demo.TensorFlowYoloDetector.create(TensorFlowYoloDetector.java:111)
        at org.tensorflow.demo.DetectorActivity.onPreviewSizeChosen(DetectorActivity.java:131)
        at org.tensorflow.demo.CameraActivity$1.onPreviewSizeChosen(CameraActivity.java:159)
        at org.tensorflow.demo.CameraConnectionFragment.setUpCameraOutputs(CameraConnectionFragment.java:421)
        at org.tensorflow.demo.CameraConnectionFragment.openCamera(CameraConnectionFragment.java:428)
        at org.tensorflow.demo.CameraConnectionFragment.access$000(CameraConnectionFragment.java:64)
        at org.tensorflow.demo.CameraConnectionFragment$1.onSurfaceTextureAvailable(CameraConnectionFragment.java:95)
        at android.view.TextureView.getHardwareLayer(TextureView.java:368)
        at android.view.View.updateDisplayListIfDirty(View.java:15175)
        at android.view.View.draw(View.java:15971)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3610)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3400)
        at android.view.View.updateDisplayListIfDirty(View.java:15193)
        at android.view.View.draw(View.java:15971)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3610)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3400)
        at android.view.View.draw(View.java:16204)
        at android.view.View.updateDisplayListIfDirty(View.java:15198)
        at android.view.View.draw(View.java:15971)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3610)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3400)
        at android.view.View.updateDisplayListIfDirty(View.java:15193)
        at android.view.View.draw(View.java:15971)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3610)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3400)
        at android.view.View.updateDisplayListIfDirty(View.java:15193)
        at android.view.View.draw(View.java:15971)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3610)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3400)
        at android.view.View.draw(View.java:16204)
        at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2690)
        at android.view.View.updateDisplayListIfDirty(View.java:15198)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:282)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:288)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:323)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2642)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2461)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2094)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1134)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6045)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
        at android.view.Choreographer.doCallbacks(Choreographer.java:672)
        at android.view.Choreographer.doFrame(Choreographer.java:608)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5441)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
04-21 09:40:52.740 1501-2367/? E/ActivityManager: Invalid thumbnail dimensions: 0x0

loadGraph method of TensorFlowInferenceInterface class:

private void loadGraph(InputStream var1, Graph var2) throws IOException {
        long var3 = System.currentTimeMillis();
        Trace.beginSection("initializeTensorFlow");
        Trace.beginSection("readGraphDef");
        byte[] var5 = new byte[var1.available()];
        int var6 = var1.read(var5);
        if(var6 != var5.length) {
            throw new IOException("read error: read only " + var6 + " of the graph, expected to read " + var5.length);
        } else {
            Trace.endSection();
            Trace.beginSection("importGraphDef");

            try {
                var2.importGraphDef(var5);
            } catch (IllegalArgumentException var9) {
                throw new IOException("Not a valid TensorFlow Graph serialization: " + var9.getMessage());
            }

            Trace.endSection();
            Trace.endSection();
            long var7 = System.currentTimeMillis();
            Log.i("TensorFlowInferenceInterface", "Model load took " + (var7 - var3) + "ms, TensorFlow version: " + TensorFlow.version());
        }
    }

p.s. demo app link: github.com/tensorflow/tensorflow/tree/master/tensorflow/examples/android

Also I have been offered to try native codepath for loading files: graphsgithub.com/tensorflow/tensorflow/issues/9343#issuecomment-295959477 but I'm not that good with C++/NDK (I just don't work with it) So there is .cc file available for loading files. I would be grateful if someone helped me to integrate it to TensorFlow example Android project. But I still hope there is solution without NDK, because is 200mb really such big size for Android 2016-2017 devices?

user924
  • 8,146
  • 7
  • 57
  • 139
  • this may help you http://stackoverflow.com/questions/25719620/how-to-solve-java-lang-outofmemoryerror-trouble-in-android – Amjad Omari Apr 23 '17 at 13:03

1 Answers1

1

I guess I have enough free memory (usually 1.0-1.5 gb are free)

That is for the device. It is not for your app.

And so is it just java android limitation?

It is a an Android runtime limitation. You have a heap limit, and your heap is likely to be fragmented.

Can I somehow solve it with java?

Probably not. You can use android:largeHeap to request a larger-than-average heap, but:

  • That may be no bigger than what you have now, on low-end devices (e.g., Android One)
  • The large heap may not be over 200MB
  • Even if the large heap is over 200MB, you may not have a single contiguous block of free heap space that is 200MB
  • Your process will be terminated rapidly when it moves into the background, if you are consuming lots of memory

Or is it possible only with NDK?

I have no idea if TensorFlow works with the NDK, as I haven't used TensorFlow. You can allocate system RAM via the NDK. Whether you can allocate 200MB of system RAM is dependent upon the amount of system RAM on the device.

because is 200mb really such big size for Android 2016-2017 devices?

200MB, as in individual block of contiguous memory, is a very big size for Android 2016-2017 devices. The age of the device has little to do with its available system RAM. There are plenty of devices manufactured today with 1GB or less system RAM installed, let alone what is free after the OS processes are running. Android One devices may ship with 512MB of system RAM, for example.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    On the last point, the more RAM memory a mobile device has, the faster it will drain the battery. Admittedly, newer generation memory uses less power (e.g. https://www.gizmodo.com.au/2013/12/samsungs-new-chips-could-put-4gb-of-ram-into-every-phone/) and batteries are improving. However, there is still a clear trade-off. – Stephen C Apr 23 '17 at 13:57
  • @StephenC apps that using neural net could be most suited for some driving assisting when people drive car, in this case we have to use some charging connection between car and phone anyway, so I don't see this as a problem – user924 Aug 31 '17 at 08:30
  • @StephenC also it doesn't mean that after loading weights (200mb), app will be using 200 mb all the time, when I loaded tiny yolo (70 mb) in my app it use later only 20-40 mb.. (whole app) it's just initial allocation and mem usage for loading file when starting the app – user924 Aug 31 '17 at 08:32
  • 1
    You are making a whole lot of assumptions here to argue that the general point about memory versus power does not apply. Your assumptions might be justified for *some* applications of Tensorflow ... – Stephen C Aug 31 '17 at 10:25
  • 1
    Your point about the memory being for startup (only) is probably not relevant. What matters for OOMEs is the maximum usage. Finally, there may be ways to optimize to reduce memory utilization, but they are beyond the scope of a "how do I solve OOME's" question like yours. Try Googling for "tensorflow memory optimization" – Stephen C Aug 31 '17 at 10:31