Most because of the heavy workload, in general, we seldom care about memory, only know the task to complete. It is only when the UI is really found or the app is running down (1.1 cards) that memory optimization is considered. Or your big company is more concerned about how fluent your phone is, and how much memory you need to manage.
1. Basic knowledge of memory management
- Because the top layer of Android is also implemented by Java, as a client, a programmer should know how to manage memory.
- And because Java, unlike the C language, can execute free to actively release memory, instead provides a Java garbage processor. But the processor does not stare at the memory at all times and cleans up directly when memory is not needed (programmers are more convenient, but not smart enough).
Memory references for Java objects are divided into the following points:
- Strong references: General new An object is a strong reference to a generic strongly referenced object GC is not recyclable and is typically stored in heap memory.
- Soft references: Typically use SoftReference to include a soft reference object, which is recycled if the object is not stored in sufficient condition
- Weak reference/Virtual reference: It is generally easy to recycle, and most of its objects are also stored in stack memory.
In memory, the storage of generic objects has the following characteristics:
- Static zone: General storage of static blocks of code, when the program began to run, there are already
- Memory Heap: General application of memory space, that is, user new out, including the global variable reference, C language malloc request memory space, all exist in heap memory.
- Memory stack: In the party scope, the internal object is destroyed each time the method executes. The entities of these objects still exist in heap memory, but the object's references are stored in the stack memory.
In the course of development, the code references often lead to a memory leak, and then we simulate a memory leak.
public class MainActivity extends AppCompatActivity { private TextView result_tv; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //2.内部方法调用外部类的某个组件进行修改 MainActivity.this.result_tv.setText("修改了UI"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } public void myClick(View v) { //1.模拟10秒后发送一个消息 new Thread(){ @Override public void run() { mHandler.sendEmptyMessageDelayed(0,10*1000); } }.start(); } private void initView() { result_tv = (TextView) findViewById(R.id.result_tv); }}
Monitor tool for 2.Android Studio
The above code, when I clicked the button, did not reach 10 seconds I closed the interface, at this time mainactivity should be closed and then destroyed, but the method of receiving information refers to the mainactivity global variables, That is, Mainactivity was not destroyed when it was supposed to be destroyed, resulting in a mainactivity memory leak. After exiting the interface I export the memory analysis file immediately, monitor clicks the following steps:
First introduce the memory module of Monitor:
The word memory jitter is that the app is in the process of memory space usage fluctuations too large, high and low fluctuation. Using the memory tool of Android Studio, you can observe the fluctuation of
A simple meaning, the highest ripple, is to represent the current memory usage has reached the trigger GC garbage collection. When the GC is working, all current threads, including Uithread, will be briefly paused until the GC has finished working. Occasionally it is not possible to create an interface lag, but if frequent triggering of GC work, it is inevitable that the interface caused the memory jitter of the reason: frequent triggering of garbage collection optimization is also simple: avoid frequent triggering of GC
The interface of the above module is parsed as follows:
As can be seen from the above, although the exit Mainactivity interface was exited, but mainactivity internal reference to a handler, and handler inside also held mainactivity. Handler performs the task in the child thread after 10 seconds of activity exit. Therefore, a memory leak is caused.
3.Eclipse plug-in Mat tool
The above code actually we already know where the memory leaks are. and the monitor tool just helps us analyze how the memory is doing. But as for how to know the memory leak also through the programmer's analysis.
The mat is the memory analyse tool, in fact, is an analysis tools, he analyzed the hprof file. So we can export the Hprof file we just generated to the mat analysis.
1. Export the Hprof file for Android Studio.
2. If you are using the mat for the 1th time, you can download the Eclipse and Mat plugins first:
:
Eclipse download
Mat download
Install the plugin for the following address:
3. The next series of diagrams explains how to import files:
5. Analysis of the overall situation:
6. Analyze the memory of the object:
After searching as:
7. Analyze the memory consumption of all classes under the package:
4. Memory leak analysis and attention points
- Most of the time, we can think of a memory leak when the UI does something that doesn't work.
- Analyze memory jitter in monitor to create a hprof report.
- If you can analyze it in Android Studio, just analyze it directly from the code and if not, you need to import it into a professional mat tool.
Of course, the above code is just an analysis of the object's operation. In Android development, there are also the following things to avoid:
1. Memory leaks due to static variables
Below I have created a tool class that references the context with the following code:
public class BaseUtil { private static BaseUtil sInstance; private final Context mContext; private BaseUtil(Context c) { mContext=c; } public static BaseUtil getInstance(Context c){ if (sInstance==null){ sInstance=new BaseUtil(c); } return sInstance; } //other methods ...}
Then in the activity, create the tool class with the following code:
public class TestActivity extends AppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); BaseUtil baseUtil = BaseUtil.getInstance(this); }}
If we start the interface first, then the static variables inside the tool class refer directly to Testactivity, if the class closes the current interface after launching a new interface, the testactivity should be destroyed at the moment, but because a reference to a static variable causes the destroyed object to not be destroyed, caused a leak in memory.
The solution is very simple, as long as the context does not directly refer to the activity of the contexts to be able to change into a application context.
2. Non-static internal classes cause memory leaks
public class TestActivity extends AppCompatActivity { private int a=0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); new Thread(){ @Override public void run() { while (true){ TestActivity.this.a+=1; SystemClock.sleep(2000); } } }.start(); }}
In the code above, I created a child thread and implemented a dead loop internally. If I quit the current activity, because the Rannable object inside the thread references the activity's global variable A, the activity cannot be destroyed without being destroyed. This causes a memory leak.
The code to solve is as follows, the following code is actually a non-static internal object into a static class, the class in order to hold activity, the activity into a weak reference object, when I click Exit activity, because runnable is a weak reference object, So the direct activity was destroyed:
public class TestActivity extends AppCompatActivity { private int a=0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); new Thread(new MyRunnable(this)).start(); } public static class MyRunnable implements Runnable{ private WeakReference<TestActivity> mTestActivityReference; public MyRunnable(TestActivity testActivity) { mTestActivityReference=new WeakReference<TestActivity>(testActivity); } @Override public void run() { while (true){ TestActivity activity = mTestActivityReference.get(); if (activity!=null){ activity.a+=1; } SystemClock.sleep(2000); } } }}
3. No need to use the listener does not remove the memory leak will occur
SensorManager manager = (SensorManager) getSystemService(SENSOR_SERVICE);Sensor lightSensor = manager.getDefaultSensor(Sensor.TYPE_LIGHT);SensorEventListener sensorEventListener = new SensorEventListener() { @Override public void onSensorChanged(SensorEvent event) { } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { }};manager.registerListener(sensorEventListener,lightSensor,SensorManager.SENSOR_DELAY_NORMAL);
In fact, listening to a light sensor is a very expensive process. So we need to log out in real time when we exit the interface that the sensor needs to listen to.
manager.unregisterListener(sensorEventListener);
Another example is that we occasionally use content watchers to implement registration:
ContentResolver cr = getContentResolver();Uri uri= Uri.parse("content://sms/");ContentObserver contentObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange, Uri uri) { super.onChange(selfChange, uri); }};cr.registerContentObserver(uri, true, contentObserver);
When you do not need to implement monitoring, you should log out directly:
cr.unregisterContentObserver(contentObserver);
The above examples abound, remember the dynamic registration Screen lock screen broadcast event, when not required to write off.
4. Memory leaks due to resource not shutting down
ContentResolver cr = getContentResolver();Uri uri= Uri.parse("content://sms/");Cursor cursor = cr.query(uri, null, null, null, null);//do you code ...cursor.close();
In addition to the cursor object, there are common IO streams, or you have played a music player, video player, remember to close the resource when not used, empty the internal buffer data.
5. Memory Leak & Memory Overflow
Memory Leak (Leak):
- Some of the objects in the process are no longer useful, but they can also be referred to GC root directly or indirectly, resulting in the inability to recycle.
Memory Overflow (OOM):
- When memory leaks too much, plus the memory used by the application itself, the accumulation of memory over time can eventually lead to an overflow of oom.
- Memory overflows when an application consumes more heap resources than the memory allocated by the Dalvik virtual machine. For example: loading large images.
6.dalvik&art
Android5.0 before using the Dalvik virtual machine, and then using the art virtual machine, here are some comparisons:
Dalvik converts bytecode to machine code at runtime, art is converted to machine code when it is installed, so installed applications take up more space, but run less time to convert, so it runs faster
Art provides better garbage collection performance by reducing the number of pauses in the program from two (analysis, cleanup) to one at a time when the program is paused, garbage collection processing in parallel while recovering newly allocated, short-life objects, and less time spent by the garbage collector
7.Allocation tracker&memory Usage
Allocation Tracker is actually a list of objects requesting memory, which allows us to see how the object is created, how many bits of memory it has requested in memory, and so on.
1. Open the monitors manager. Click on the button below to help us record how many objects have requested memory space during an operation window, which is a button that starts and ends the record:
2. When the record is completed, the system will make a record of the memory space and the object requested during that time period, select group by Allocator, and click on the Item right button jump to source can view the code of the request memory:
3. The above action is the memory that I recorded when I clicked the button 3 times in mainactivity. These 3 operations create 1 immutable strings and three new application strings, and because Baseutil is a singleton, it doesn't matter how many times it's been ordered. The code is as follows:
public void myClick(View v) { String s=new String("aaaa"); BaseUtil.getInstance(this);}
We can use this tool as an application for memory observation tool. Here again, there is a tool that can help us to roughly see if the memory is occupied:
This tool is the most important to help us roughly calculate the current interface is a memory leak, for example, when the application started, the interface display, and then click to exit the application, if using the tool found activities is not 0, indicating that the interface has a memory leak. Or the interface is started, but the number of view is unusually increased, also consider whether there is a memory leak.
8.Lint Detection Tools
The lint tool is primarily used to optimize the entire application, and in Android Studio2.3 we can call lint tools like this:
The following panel lists the issues that occur with the current project:
Suspect 1: Tell us that the string can be replaced with res/string
Suspect 2:handler must become static or memory leaks may occur
Suspect 3: The declared variable must be prefixed with the final modifier
Suspect 4: The v parameter in the Click has not been used.
Note: The above suspicion does not need to start the application can be detected, and not only to check the memory leak, he included the resources are not referenced on the package, whether the spelling of the word support hump, and so on, depending on the specific detection, and the system to give the recommendations are not necessarily modified, you can let the programmer according to their own needs to modify
9.LeakCanary
We can either use the memory leak detection tool in Android Studio, or use the instrumentation tool in the app, and the following is a recommended tool for leakcanary in the memory provided by the Square company. It makes it easy to give users hints when a memory leak occurs in the application. Its github address, let's see how it's used:
1. Add dependencies to the app's Gradle file:
dependencies { ... debugCompile ‘com.squareup.leakcanary:leakcanary-android:1.5.1‘ releaseCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5.1‘ testCompile ‘com.squareup.leakcanary:leakcanary-android-no-op:1.5.1‘}
2. Under your application, add the following code:
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } LeakCanary.install(this); // Normal app init code... }}
3. In activity, simulate a memory leak (exit the interface within 10 seconds of clicking the button):
public class MainActivity extends AppCompatActivity { private TextView result_tv; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //2.内部方法调用外部类的某个组件进行修改 MainActivity.this.result_tv.setText("修改了UI"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } public void myClick(View v) { //1.模拟10秒后发送一个消息 new Thread(){ @Override public void run() { mHandler.sendEmptyMessageDelayed(0,10*1000); } }.start(); } private void initView() { result_tv = (TextView) findViewById(R.id.result_tv); }}
4. After you've deployed your app/memory leak, you'll find a new leak in your phone. Bravery helps you detect a memory leak, but only for applications that are configured with parameters that need to be detected within the application. Sure, you're going to have to allow him to set specific permissions.
5. When the memory leaks, a prompt appears:
This indicates that when the interface exits, the child thread also holds the activity's global variable handler object, resulting in a memory leak caused by mainactivity not being destroyed.
10.UI optimization principle how UI lag comes
- Direct access to the network in the main thread (although this operation was banned after version 4.4)/Intensive IO Operations/Execute SQL operations.
- Continuously request space in a method or block of code and perform GC cleanup. Causes a large number of operations to be performed by the GC in a short time. Processing of the GC pauses the operation of the main thread.
- In general, the main thread/ui a time-consuming operation.
Mechanism for rendering refreshes
1. First of all, you need to know that Android's ideal refresh rate is 60Hz, that is, 1 seconds the UI draws the frame number is ideal 60 times.
2. According to the above calculation, 1 seconds =1000ms, then the refresh time of each frame is 10000ms/60=16.6ms. We say that the Android ideal has a refresh time of 16.6ms per frame.
3. The logic for normal refresh of each frame in the above figure must be within 16 milliseconds, but if there is more than 16 milliseconds for a single frame refresh, there will be a drop frame (that is, the 24-millisecond frame cannot be displayed for more than the time, drawing the next frame directly).
4. Here is a noun called 60fps, which refers to the number of frames drawn within a second. Within 60fps, the system will get a continuously sent VSync (vertical refresh) signal to render, and to draw normally.
5. To understand the so-called VSync vertical refresh, first understand the 2 concepts:
1) Refresh rate: The number of times the screen is refreshed in one second-there are hardware parameters, such as 60HZ.
2) Frame Rate:gpu The number of frames to draw the operation in one second, for example: 60fps.
6. Graphics processor (GPU), also known as the display core, visual processors, display chips, is a special kind of computer/mobile devices like the operation of the microprocessor. GPU Refresh will help us to calculate the UI components such as texture texture and three-dimensional graphics polygons
The 7.VSYNC refresh principle is as follows:
8. How to locate the lag of the view itself.
- 可以使用Allocation Tracking来定位大致的情况- 可以使用TraceView来确定详细的问题所在。
Allocation Tracking Positioning
The address of a project is provided first. Click the 2nd button on the first page to enter the following interface to detect the button:
We can look at the top of the button to see which class of our application is using the memory highs:
We can see in the above record file that one of our own classes in our application occupies 20% of the memory space at the time. Next, you can record the package in the upper-right corner that contains the class for analysis:
1. Click the icon in the top left corner to show the pie chart
2. Above we have found a class that occupies a large memory control, causing the UI to be stuck. Record the package name, enter it in the input box in the upper right corner, and the pie chart will have a corresponding change at the moment.
3. There is a button on the right to set the way the picture is displayed. This is the pie chart by default.
4. The pie chart extends outward from the first layer of the package name to the inside. Just click on the bottom 2nd level, you can find the corresponding class, and the innermost layer, here is COM.
5. Find the outer layer of activity and you will find that the memory of char[] and string is very much occupied. This exit can present a memory leak.
Click on the Activity class and right-jump to source. You can see that the following code has requested most of the memory space and destroyed it, causing GC memory jitter, the code is as follows:
/** * 排序后打印二维数组,一行行打印 */public void imPrettySureSortingIsFree() { int dimension = 300; int[][] lotsOfInts = new int[dimension][dimension]; Random randomGenerator = new Random(); for(int i = 0; i < lotsOfInts.length; i++) { for (int j = 0; j < lotsOfInts[i].length; j++) { lotsOfInts[i][j] = randomGenerator.nextInt(); } } for(int i = 0; i < lotsOfInts.length; i++) { String rowAsStr = ""; //排序 int[] sorted = getSorted(lotsOfInts[i]); //拼接打印 for (int j = 0; j < lotsOfInts[i].length; j++) { rowAsStr += sorted[j]; if(j < (lotsOfInts[i].length - 1)){ rowAsStr += ", "; } } Log.i("ricky", "Row " + i + ": " + rowAsStr); }}public int[] getSorted(int[] input){ int[] clone = input.clone(); Arrays.sort(clone); return clone;}
TraceView positioning
TraceView is mainly used to analyze the time-consuming operation of the main thread, and then see how to operate the tool.
You can click Start trace monitoring and then run an operation that you think is time consuming, such as the one we just caused the GIF to stutter:
The above panel mainly describes the following:
1. Representing the right side is the density of the main thread performing tasks
2. Process execution for stack tasks
3. On which point the current time axis is represented
4. The total detection timeline, that is, the start and end time of the point we just started.
5. Double-click the timeline to zoom in on the time axis.
6. Hold down and drag to a position to make the middle part of the timeline larger.
7. Each of the 2 points in the middle of the timeline represents a time period in which a method executes.
In addition to the timeline, there are the following method panels, which by default are called by the method from top to bottom in the time period that you record:
You can also search for the corresponding method and then expand the details of the method, which describes the internal structure:
The parent represents an external method that calls the method
Children represents other methods that are contained within the method.
Incl Cpu time
CPU time consumed by a function that contains internal calls to other functions for CPU time
EXCL Cpu Time
The CPU time that a function consumes, but does not contain the CPU time that is consumed by the internal call to other functions
Incl Real time
The real time (in milliseconds) that a function runs, containing the actual time taken to invoke other functions
EXCL Real Time
The real time (in milliseconds) that a function runs, without the real time it takes to invoke other functions
Call+recur Calls/total
The number of times a function is called and the percentage of the total number of calls that the recursive call takes
How the 11.UI rendering mechanism works in depth
Rendering is the most common feature of the application, as is the development of any application, on the one hand, the designer requires the user to show the most usability of the transcendent experience, on the other hand, those gorgeous pictures and animations, not on all devices can be Liu Chang run.
The rendering pipeline for the Android system is divided into two key components: CPU and GPU, which work together to draw pictures on the screen, each with a specific process defined by itself. We have to follow these specific rules of operation to achieve results.
The CPU itself actually has a display function, but the CPU has to do a lot of things, and in order to make the display more professional, but also added a dedicated to display the image of the processor GPU. The image processor is capable of achieving rasterized image display. As an example:
We need to know that the process of converting a UI object into a series of polygons and textures is certainly time consuming, and it is also time consuming to upload data from the CPU to the GPU. So obviously, we need to minimize the number of object conversions and the number of uploads, fortunately, the OpenGL ES API allows data to be saved after uploading to the GPU, and when we next draw a button, we just need to reference it in the GPU memory. Then tell OpenGL how to draw it, a rule of thumb: the optimization of rendering performance is to upload the data to the GPU as much as possible, and then save the data as long as possible without modification, because we waste valuable processing time every time we upload resources to the GPU.
The Android system has done a lot to reduce and re-use GPU resources, and there's absolutely no need to worry about it. For example: any of the resources provided by our topic, such as bitmaps, drawables, etc., are packaged together into a unified texture and then uploaded to the GPU using the grid tool, such as nine patches and so on, so that every time I need to draw these resources, we do not have to do any conversion, they have been stored in the GPU, greatly speeding up the display of these view types.
Now that the Android system has solved most of the performance issues, unless we have a higher requirement, we basically don't find GPU-related problems, and then there is a GPU performance problem bottleneck that bothers every programmer, which is over-drawing.
Over-Drawing
In fact, when a UI interface is rendered after multiple rendering, the first rendered background color value will be overwritten by the background rendered behind, resulting in wasted painting, in order to understand whether the painting waste is serious, we will draw divided into 4 levels, red represents a serious over-drawing, the most ideal is 1 levels of paint (gray/Purple):
The following code is provided for the user to practice optimizing the project address, importing the project, and opening the over-drawn switch:
General Select the second option, if there is red-green blindness, you can choose the last item. After the click, the interface is as follows, according to the above-mentioned rendering level, Genymotion's interface does quite well:
Next, start our project:
First you'll notice that the title of the app is over-drawn. Why does it lead to this? Because at the time of drawing, the theme of the app first adds a layer of background to the entire interface. We can remove this background and add it in the OnCreate () method:
getWindow().setBackgroundDrawable(null);
The effect is as follows, and you will notice that the background of the title changes from Level 2 to Level 1:
In fact, you will find that the background of the activity in the code and fragment background are all the same white, after removing the fragment background, the 2-level green background color is gone, programming white:
The item layout, the picture to the right of the module inside the container all the background is removed, the interface is as follows, although the click of the ripple effect caused by the excessive drawing, but this because the effect of the need to waste performance is possible:
Not finished:
Android Memory Management Analytics