I've found a memory leak in Android 5.x Camera2 API which I also reported. The problem is when you use Android Lollipop device that has Camera2 API implemented in LEGACY
mode. On such devices, calling context.getSystemService(Context.CAMERA_SERVICE)
causes context
to be retained so that it won't be garbage collected.
If this context
is your activity that is started multiple times, you can end up with hanging references to dozens of instances of your activity that are never garbage collected.
The issue appears to happen only on Lollipop devices that have Camera2 API implemented in LEGACY
mode (e.g. HTC One M8, Samsung Galaxy S4), while it does not happen on Samsung Galaxy S6 which implements Camera2 API in FULL
mode.
To demonstrate the issue, I've created a small demo app. The app contains two activities: first that contains a button which calls the second activity. The second activity obtains the CameraManager
and queries the level of Camera2 API support for first back-facing camera and returns the result to first activity. If you run the app on device that implements Camera2 API in LEGACY
mode, after tapping the button 98 times, causing GC and then dumping HPROF you will see exactly 98 live instances of Main2Activity
, like this http://www.pohrani.com/f/1H/gs/4EFlHKoj/sgs4.png
If you do the same on device that implements Camera2 API in FULL
mode, you will see 0 live instances of Main2Activity
, like this http://www.pohrani.com/f/2q/bV/4srUZIJL/sgs6.png
Is there a way to workaround this leak?
One might ask why am I doing this? At our company, we are developing barcode and OCR scanning solutions and also a famous PhotoMath app. So we have a scan activity that controls the camera and scanning process. While starting up, activity checks if device supports Camera2 API in either FULL
or LIMITED
mode and attempts to use it for better performance, whilst if Camera2 API is in LEGACY
mode, then we prefer using camera management using old camera API, as we do on pre-Lollipop devices.
Because of the mentioned memory leak, whenever a client that has integrated our SDK into its app starts the scan activity, performs a scan and obtains the result, one instance of scan activity will be leaked due to the bug. If client scans a lot, this can eat up a more than 20 MB of memory - a serious issue!
So if someone knows how to make a workaround for this issue, I'll be eternally grateful!
The best way to avoid memory leaks in C++ is to have as few new/delete calls at the program level as possible – ideally NONE. Anything that requires dynamic memory should be buried inside an RAII object that releases the memory when it goes out of scope.
The memory leak occurs, when a piece of memory which was previously allocated by the programmer. Then it is not deallocated properly by programmer. That memory is no longer in use by the program. So that place is reserved for no reason. That's why this is called the memory leak.
Memory leak occurs when programmers create a memory in heap and forget to delete it. The consequences of memory leak is that it reduces the performance of the computer by reducing the amount of available memory.
Is there a way to workaround this leak?
You could call getSystemService()
on the Application
singleton. So, instead of:
getSystemService(CAMERA_SERVICE)
you would use:
getApplicationContext().getSystemService(CAMERA_SERVICE)
If your assessment is correct, then this will cause those additional references to be to the existing Application
singleton, which is always around in your process. It's effectively "pre-leaked", and you cannot leak it further by having more references to it.
This is an Android bug that was fixed in L MR1.
Basically, the CameraManager retained a reference to the context it was created with, and then connected to the camera service. This connection kept the camera manager instance alive indefinitely, and therefore also kept the Context alive indefinitely.
This was fixed in L MR1 to correctly allow CameraManager objects to be reclaimed when no longer referenced.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With