Reload address: http://www.jianshu.com/p/402225fce4b2
JVM Memory Management
Java uses GC for memory management.An in-depth knowledge of JVM memory management is recommended, Understanding Java Virtual Machines in depth.As for memory leaks, there are several strategies for memory allocation in JVM.
- Static
Static memory, which is allocated at the time the program is compiled, persists throughout the program's run. It stores static data, global static data, and some constants.
- Stacked
When a method is executed, the storage of some internal variables of the method can be created on the stack, and these storage units are automatically commented out when the method is executed.Stack memory includes allocations that run fast because they are built into the processor.Of course, the capacity is limited, and a stack of contiguous memory area, the size is determined by the operating system, he goes in and out, complete without fragmentation, efficient and stable operation
- Heap
Also known as dynamic memory.We usually use new to request a memory allocation.This is also the key storage where we discuss memory leak optimization.GC reclaims the garbage memory in the heap memory based on memory usage.Heap memory is a discontinuous area of memory. Frequent new/remove can cause a lot of memory fragmentation, frequent GC recycling can cause memory jitter, which can also consume the performance of our applications.
We know we can call System.gc(); do memory recycling, but GC may not necessarily execute.Is there anything we can do about the GC mechanism?In fact, we can make GC recycle memory better by declaring some reference tags.
- StrongReference The GC cannot recycle him at any time, even if memory is low, the system will throw an exception OutOfMemoryError directly and the recycling process will not terminate
- SoftReference does not reclaim objects of this type of reference when there is enough memory, only when there is not enough memory to reclaim, when GC is in progress
- WeakReference GC runs and terminates after GC is recycled
- PhantomReference If an object is associated with a virtual reference, it is possible to be recycled by the garbage collector at any time, just as there is no reference associated with it
In order to prevent memory overflow during development, soft and weak references can be used whenever possible when dealing with objects that are memory-intensive and have a long life cycle.
Tip
Member variables are all stored in the heap (including basic data types, referenced object entities) because they belong to classes, and class objects are ultimately to be new er
Basic data types and references to local variables exist on the stack, and the applied object entities are stored on the stack.Because they are variables in a method, the lifecycle ends with the method
Definition of memory leak
When an object is no longer needed and should have been recycled, another object in use holds its reference, which prevents the object from being recycled by the GC.This causes the object that should have been recycled to remain in heap memory instead of being recycled, resulting in a memory leak
Difference between memory leak and memory overflow
Memory Leak
Some objects in the process are no longer of use value, but they can also be referenced directly or indirectly to the GC Root leading to non-recyclability.When there are too many memory leaks, combined with the memory used by the application itself, cumulative memory overflow eventually results in OOMMemory Overflow (OOM)
Memory overflow occurs when the heap resource of the application exceeds the memory allocated by the Dalvik virtual machine
The impact of memory leaks
Apply Carton
Leaked memory affects GC memory allocation, too many memory leaks affect application execution efficiencyApply Exception (OOM)
Too many memory leaks will eventually cause Dalvik to allocate memory for OOM
Common memory leaks in Android development
Memory leak caused by a single case
- Error example
When getInstance is called, if the context passed in is the context of the Activity.As long as this case is not released, then this
Activity will not be released until the process exits.
public class CommUtil {
private static CommUtil instance;
private Context context;
private CommUtil(Context context){
this.context = context;
}
public static CommUtil getInstance(Context mcontext){
if(instance == null){
instance = new CommUtil(mcontext);
}
return instance;
}
- Solution
Instead of using Activity's Content when you can use Application's Context, the life cycle of the Application follows the cycle of the entire process
Memory leak caused by static instance creation by a non-static internal class
- Error example
private static TestResource mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mManager == null){
mManager = new TestResource();
}
}
class TestResource {
}
- Solution
Modify a non-static internal class to a static internal class.(Static internal classes do not implicitly hold external classes)
Memory leak caused by Handler
- Error example
MHandler is an instance of Handler's non-static, anonymous internal class, so it holds a reference to the external class Activity. We know that Message queuing is constantly polling for messages in a Looper thread. When this activity exits, there are still unprocessed messages in the Message queue or messages being processed, while M in the Message queueEssage holds a reference to an instance of mHandler, and mHandler holds a reference to an activity. As a result, the activity's memory resources cannot be recycled in a timely manner, causing a memory leak.
private MyHandler mHandler = new MyHandler(this);
private TextView mTextView ;
private static class MyHandler extends Handler {
private WeakReference<Context> reference;
public MyHandler(Context context) {
reference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if(activity != null){
activity.mTextView.setText("");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textview);
loadData();
}
private void loadData() {
Message message = Message.obtain();
mHandler.sendMessage(message);
}
- Solution
Create a static Handler internal class and then use weak references to the objects held by the Handler so that the objects held by the Handler can also be recycled on recycle, which avoids activity leaks, but there may still be messages to be processed in the message queue of the Looper thread, so when we are in Activity's Dextroy, or Stop should remove messages from the message queue
private MyHandler mHandler = new MyHandler(this);
private TextView mTextView ;
private static class MyHandler extends Handler {
private WeakReference<Context> reference;
public MyHandler(Context context) {
reference = new WeakReference<>(context);
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if(activity != null){
activity.mTextView.setText("");
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView)findViewById(R.id.textview);
loadData();
}
private void loadData() {
//...request
Message message = Message.obtain();
mHandler.sendMessage(message);
}
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
}
Memory leak caused by thread
- Error example
Asynchronous tasks and Runnable s are both anonymous internal classes, so they have an implicit reference to the current Activity.If the task is not completed before the Activity is destroyed, it will cause the Activity's memory resources to not be reclaimed, causing a memory leak
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
}.execute();
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(10000);
}
}).start();
- Solution
Static internal classes are used to avoid memory resource leaks from the Activity. Of course, the corresponding task AsyncTask::cancel() should be canceled when the Activity is destroyed to avoid wasting resources when the task is executed in the background.
static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<Context> weakReference;
public MyAsyncTask(Context context) {
weakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
MainActivity activity = (MainActivity) weakReference.get();
if (activity != null) {
//...
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
SystemClock.sleep(10000);
}
}
new Thread(new MyRunnable()).start();
new MyAsyncTask(this).execute();
Memory leak caused by resource not closing
- Error example
Use of resources such as BraodcastReceiver, ContentObserver, File, Cursor, Stream, Bitmap should be closed or logged off in time when the Activity is destroyed, otherwise these resources will not be recycled, causing a memory leak
-
Solution
Close or log off Activity in time when it is destroyed
Use static Activity and View
- Error example
static view;
void setStaticView() {
view = findViewById(R.id.sv_button);
}
View svButton = findViewById(R.id.sv_button);
svButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticView();
nextActivity();
}
});
static Activity activity;
void setStaticActivity() {
activity = this;
}
View saButton = findViewById(R.id.sa_button);
saButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticActivity();
nextActivity();
}
});
- Solution
Static applications should be null in time, and View and Activity are generally not recommended to be static
System services registered, but onDestory is not unregistered
- Error example
SensorManager sensorManager = getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_FASTEST);
- Solutions
//Remove monitoring when not needed
sensorManager.unregisterListener(listener);
Memory leaks occur if unneeded listeners are not removed
- Error example
//add listen, put in collection
tv.getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
@Override
public void onWindowFocusChanged(boolean b) {
//Listens for the view to load, and calculates its width and height when the view loads.
}
});
- Solution
//Be sure to remove this monitor after calculation
tv.getViewTreeObserver().removeOnWindowFocusChangeListener(this);
//Tip
tv.setOnClickListener();//Listen for recycled objects without regard to memory leaks
tv.getViewTreeObserver().addOnWindowFocusChangeListene,addListen, put into collection, need to consider memory leak