Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid memory leak in context.getSystemService(Context.CAMERA_SERVICE)?

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!

like image 370
DoDo Avatar asked Aug 11 '15 13:08

DoDo


People also ask

How can memory leaks be avoided?

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.

What is a memory leak give an example how it can be avoided?

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.

What are the causes of memory leaks?

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.


2 Answers

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.

like image 187
CommonsWare Avatar answered Oct 04 '22 16:10

CommonsWare


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.

like image 39
Eddy Talvala Avatar answered Oct 04 '22 17:10

Eddy Talvala