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 SurfaceView
s 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:
Delete this class. Move all of this logic into the activity (or fragment), where you have direct access to the widgets.
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.Have your activity/fragment hold an instance of
CommentsAudioPlayer
, and make the fields inCommentsAudioPlayer
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
Android Camera Surfaceview Orientation
How to Put Media Controller Button on Notification Bar
Error: Status{Statuscode=Developer_Error, Resolution=Null}
How to Make My App Receive Broadcast When Other Applications Are Installed or Removed
Complete Working Sample of the Gmail Three-Fragment Animation Scenario
Bypass Android Usb Host Permission Confirmation Dialog
Sha1 Key for Debug & Release Android Studio MAC , How to Generate Sha1 Release Keys in MAC
How to Check If Url Is Valid in Android
Android: How to Get Value of an Attribute in Code
Error Inflating Class Android.Support.V7.Widget.Toolbar
How to Use Getsystemservice in a Non-Activity Class (Locationmanager)
Preventing Status Bar Expansion
How to Get Current Flavor in Gradle
Which Correct Flag of Autoconnect in Connectgatt of Ble
How to Verify That an Android APK Is Signed with a Release Certificate
Android: Share Plain Text Using Intent (To All Messaging Apps)
Download Files and Store Them Locally with Phonegap/Jquery Mobile Android and iOS Apps
Ionic Build Android | Error: No Installed Build Tools Found. Please Install the Android Build Tools