Android:Static Fields and Memory Leaks

Android : Static Fields and Memory Leaks

In Java/Android a static variable or constant will not be garbage collected. It just stays there once the class that holds it is loaded via a class loader. The class loader is afaik always the same for all classes inside your app and its the one that has static references to all your classes (to e.g. MyInnerClass.class). Since the class loader does not go away your classes won't do that either since they are referenced & therefore not garbage collectable.

Like in your example

public class SomeClass extends SurfaceView {
private static Context myContext;

public MyInnerClass(Context context){
myContext = context; // This is bad.
}
}

That is indeed bad. Even if no reference to SomeClass exists (e.g. the Activity that showed your custom SurfaceView has ended) the static reference to the Context (and any other static variable / constant in SomeClass will remain. You can consider all of them leaked since it is not possible to garbage collect that Context etc. If you have a regular variable reference something then once the instance that contains that variable has no more references to it the whole instance including its references to other things can and will be garbage collected. Java can even handle circular references fine.

For constants you want that to happen and it is usually not bad since the amount of constants and the amount of memory they occupy is not large. Also constants don't (should not) reference other instances that take up large amounts of memory like Context or Bitmap.

Besides the possibility to create memory leaks through static variables you may also create problems if you don't want to have only a single thing for all instances at the same time. For example if you save the Bitmap of your SurfaceView in a static variable you can't have two different images. Even if the two SurfaceViews are not displayed at the same time you could run into problems since each new instance will probably overwrite the old image and if you go back to the other SurfaceView you unexpectedly show the wrong image. I am almost sure you don't want to use static here.

The fact that your inner class is a static class does not mean that you have to use static variables - it just means that it behaves more like a static method since it can't use the instance variables (the ones that are not static) in your class.

To avoid memory leaks you simply should not use static variables at all. There is no need to use them unless you do special stuff (e.g. counting instances of a class). Constants are fine.

Memory leaks when using static context items in android

Static UI elements make no sense in Android First off, UI objects are bound to a specific Activity. They can't be used from other activities or displayed outside of their Activity. So making them static doesn't bring value

Secondly, this will always be a memory leak. Each view has a reference to its Activity. Putting an Activity in a static variable means it can't be garbage collected, because there's a valid reference to it. That will basically cause every variable in that Activity to leak. Including the UI elements, which tend to be memory hungry (each image takes 4 bytes per pixel).

You need to rethink what you're trying to do with this code. I actually can't tell. If you made them static so you can change them from other activities- don't do that. Make them based off a model object, and alter the data in the model instead. Let the UI reinitialize itself based off the model.

How do I prevent memory leak caused by context class in static fields

Do not pass Context in the Repository except pass AppDatabase instance directly.

AppDatabase is used as Singleton throughout the application So you just initiate it once probably in Application class or in some other Singleton, and use the same Object everywhere.

It will be easy to create/inject Dependencies if you use any dependency injection framework like Dagger2 or Dagger-Hilt.

You can remove var for constructor field to make it work then it will not hold the reference globally. Thx to @Henry Twist .

class Repository private constructor(context: Context) {
private val TAG = javaClass.simpleName
var appDatabase: AppDatabase = AppDatabase.getInstance(context.applicationContext)
companion object {
@Volatile
private var instance: Repository? = null
@JvmStatic
fun getInstance(context: Context) = instance
?: synchronized(this) {
instance
?: Repository(context).also { instance = it }
}
}
}


Memory leak for static declaration of context and INSTANCE , how do I alter it?

It's safe to store application context in a static field, you can simple call context.getApplicationContext() on any context reference you get before storing it in a static field.

The application context is a singleton anyway and you cannot leak it.

is static variables cause memory leak in android?

Your example will not cause a memory leak, but if you point to an activity or view context, it will.

So you can safely store any primitive static variable in your class.

Do not place Android context classes in static fields; this is a memory leak - Lint Warning for static View

Do not put widgets in static fields.

Options include:

  1. Delete this class. Move all of this logic into the activity (or fragment), where you have direct access to the widgets.

  2. Use an event bus (LocalBroadcastManager, greenrobot's EventBus, etc.). Have your code here post messages on the bus when the state changes. Have your UI (activity or fragment) subscribe for messages on the bus and update the widgets.

  3. Have your activity/fragment hold an instance of CommentsAudioPlayer, and make the fields in CommentsAudioPlayer non-static.

Of the three, the first option would be simpler, cleaner, less memory-intensive, and faster to execute.

Warning: Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

Simply pass it as a parameter to your method. There is no sense in creating a static instance of Context solely for the purpose of starting an Intent.

This is how your method should look:

public static void log(int iLogLevel, String sRequest, String sData, Context ctx) {
if(iLogLevel > 0) {

Intent intent = new Intent(ctx, LogService.class);
intent1.putExtra("UPDATE_MAIN_ACTIVITY_VIEW", "UPDATE_MAIN_ACTIVITY_VIEW");
ctx.startService(intent);
}
}

Update from comments on question: Cascade the context from the initiating activity (via constructor parameters or method parameters) right up to the point you need it.



Related Topics



Leave a reply



Submit