journeyapps / zxing-android-embedded

Barcode scanner library for Android, based on the ZXing decoder
https://journeyapps.com/
Apache License 2.0
5.68k stars 1.26k forks source link

Excessive memory usage when scanning continuously #638

Open shlusiak opened 3 years ago

shlusiak commented 3 years ago

Description of the problem:

I'm building a continuous scanner using library version 4.2.0 and I found my device (Samsung S20, Android 11) quickly draining battery due to garbage collection. An older device with Android 6 throws error due to out of memory.

I'm using the CameraPreview class directly and request continuous previews using requestPreview(callback).

From my understanding, this asks the Android system for a camera preview and receives it https://github.com/journeyapps/zxing-android-embedded/blob/40260272fcff4f14181803495e7d370c23e35db7/zxing-android-embedded/src/com/journeyapps/barcodescanner/camera/CameraManager.java#L93-L97

The byte array is allocated by the system and on my Samsung S20 is 1920x864, and 2488320 bytes (~2.3 MB). I assume this byte array is unowned and cannot be returned and will lie around after processing, waiting to be garbage collected. The SourceData's rotation is 90, and the cropRect is Rect(86, 614 - 777, 1305).

I then receive the SourceData and call .createSource() on it to get my PlanarYUVLuminanceSource. The RawImageData.rotateCW() then creates a complete new giant byte array with the rotated image data, which will be 1920x864 ~ 1.6 MB:

https://github.com/journeyapps/zxing-android-embedded/blob/40260272fcff4f14181803495e7d370c23e35db7/zxing-android-embedded/src/com/journeyapps/barcodescanner/RawImageData.java#L87-L93

The RawImageData.cropAndScale() will then also create another byte buffer with 691x691 ~ 450 KB and will immediately drop the one from the rotation.

https://github.com/journeyapps/zxing-android-embedded/blob/40260272fcff4f14181803495e7d370c23e35db7/zxing-android-embedded/src/com/journeyapps/barcodescanner/RawImageData.java#L28-L35

So for a single scan pass, my device has allocated 2.3 MB + 1.6 MB + 450 KB = 4.3 MB of memory that will have to be garbage collected. Targeting 10 passes / second I'd hit memory limits very quickly.

I feel this can be optimised:

Any thoughts on this?

shlusiak commented 3 years ago

Looks like #398 or #364 could be related.