First, the story begins

Interviewer: Do you encounter lag problems in your development? How do you monitor it?

Guy: Uh… I have not encountered the problem of lag, the quality of the code I usually write is relatively high, there will be no lag.

Interviewer:…

This may seem like a fine answer, but if you do say it in an interview they will assume you have zero experience in caton monitoring and optimization.

This topic, I believe that most of the students with two years or more work experience should be able to give a general idea.

Caton’s reasons:

The main thread is blocked. During development, the main thread may be blocked by:

  • The main thread is doing a lot of I/O: Write a lot of data directly to the main thread to facilitate code writing
  • The main thread is doing a lot of calculations: the code is not written properly, and the main thread is doing complex calculations
  • Lots of UI drawing: The interface is too complex and UI drawing takes a lot of time
  • The main thread is waiting for A lock: the main thread needs to acquire lock A, but A child thread currently holds the lock A, causing the main thread to wait for the child thread to complete the task.
  • .

But ask a little deeper:

  • After the application goes online, the program frequently freezes. How can I locate the problem?
  • When encountering OOM, how to locate the actual cause of memory overflow?
  • How to monitor online performance without affecting performance?

Friends who have been to big factories for interviews will know that big factories often ask such questions, mainly because once the occurrence of lag will be intuitively felt by users, while other problems are difficult to be found in time: such as high memory occupancy, consumption of flow, etc. If the user experience is not good, we are likely to uninstall our App, which will cost the company high user costs. Therefore, it is our developer’s dereliction of duty to lose users due to performance problems.

Ii. How to deal with performance problems?

First of all, if you are engaged in client development, you should know that the process of solving the lag is often tortuous, and some of them are not as simple and superficial as we think. Most of the time, most of the lag is difficult to find in time, can not reproduce the lag, often appear in the online user’s real use process, this kind of lag is often closely related to the machine performance, mobile phone environment, and even operating preferences and other factors.

It’s hard to get a direct insight into the root cause of the lag from the user’s “nice card” description. Some even don’t know what the scene is, so it’s hard to reproduce it exactly, so it’s kind of confusing.

As one of the most important resources for computer programs to run, memory needs to be reasonably allocated and recycled during the running process. Unreasonable memory occupation may cause the user application to run slow, ANR, or black screen, or cause the user application to crash OOM (out of Memory).

We need to maintain excellent fluency and stability on various machine resources, and memory optimization is a must. However, even if we have access to Bugly online exception collection platform, we cannot guarantee to find the reason of OOM through the exception log. For the vast majority of OOM, the exception log shows the straw that broke the camel’s back, not the direct cause.

Iii. How to monitor online performance?

The following is a summary of several popular and effective monitoring methods:

1 Based on message queues

1.1 Replace Looper Printer

Looper exposed a method

    public void setMessageLogging(@Nullable Printer printer) {
        mLogging = printer;
    }
Copy the code

Looper’s loop method has this code

    public static void loop() {
        ...
        for (;;) {
           ...
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
Copy the code

If logging is not empty, Looper will be called loggy. println. We can calculate the time difference between Looper and message acquisition through Printer setting. If the time is too long, it means that Handler processing time is too long. By simply printing out the stack information, you can locate the time-consuming code. However, println method parameters involve string concatenation, so this method is recommended only in Debug mode. Open source libraries based on this principle are represented by BlockCanary, which is the core code of BlockCanary:

Class: LooperMonitor

public void println(String x) { if (mStopWhenDebugging && Debug.isDebuggerConnected()) { return; } if (! MStartTimestamp = system.currentTimemillis (); mStartTimestamp = system.currentTimemillis (); mStartThreadTimestamp = SystemClock.currentThreadTimeMillis(); mPrintingStarted = true; startDump(); } else {isBlock final Long endTime = system.currentTimemillis (); mPrintingStarted = false; if (isBlock(endTime)) { notifyBlockEvent(endTime); } stopDump(); // Dump stack information}} Private Boolean isBlock(long endTime) {return endtime-mstartTimestamp > mBlockThresholdMillis; }Copy the code

The principle is that the time difference between Looper and message processing, say more than 3 seconds, is considered to be delayed. You can study the details of the source code, such as message queue only one message, separated by a long time before there is a message queue, this situation should be handled, BlockCanary is how to deal with it?

I tested this in BlockCanary and this problem did not occur, so how does BlockCanary deal with it? StartDump () will eventually execute an AbstractSampler class mRunnable via Handler:

abstract class AbstractSampler { private static final int DEFAULT_SAMPLE_INTERVAL = 300; protected AtomicBoolean mShouldSample = new AtomicBoolean(false); protected long mSampleInterval; private Runnable mRunnable = new Runnable() { @Override public void run() { doSample(); // startDump was set to true when called Stop set when false if (mShouldSample. The get ()) {HandlerThreadFactory. GetTimerThreadHandler () postDelayed (mRunnable, mSampleInterval); }}};Copy the code

As you can see, calling doSample followed by mRunnable through Handler is equivalent to calling doSample in a loop until stopDump is called.

The doSample method has two class implementations, StackSampler and CpuSampler, and analyzes the stack by looking at the doSample method of StackSampler

protected void doSample() { StringBuilder stringBuilder = new StringBuilder(); For (StackTraceElement StackTraceElement: mCurrentThread.getStackTrace()) { stringBuilder .append(stackTraceElement.toString()) .append(BlockInfo.SEPARATOR); Synchronized (sstackmap.size () == mMaxEntryCount &&) {// synchronize (sstackmap.size () == mMaxEntryCount &&) mMaxEntryCount > 0) { sStackMap.remove(sStackMap.keySet().iterator().next()); Sstackmap.put (System.currentTimemillis (), stringBuilder.toString())); }}Copy the code

Therefore, BlockCanary allows you to call several methods in a row and find out exactly which method takes time by opening a loop to retrieve stack information and save it to the LinkedHashMap to avoid miscalculation or missed detection. The core code is analyzed here first, other details we can go to see the source code.

1.2 Insert an empty message to the message queue

That’s the way to look at it.

An empty message is inserted into the head of the main thread message queue every one second through a monitor thread. Assuming that the message is not consumed by the main thread after 1 second, the blocking message takes between 0 and 1 second to run. In other words, if we need to monitor a 3-second delay and the header message is still not consumed in the fourth poll, we can determine that the main thread has a delay of more than 3 seconds.

2. Pile

The compilation process is staked (using AspectJ, for example), with time-monitoring code at method entrances and exits. The original method:

public void test(){
    doSomething();
}
Copy the code

After compiling the peg, the method looks something like this

public void test(){ long startTime = System.currentTimeMillis(); doSomething(); long methodTime = System.currentTimeMillis() - startTime; // Calculate method time}Copy the code

And, of course, here’s how it works, and it might actually need to be encapsulated, something like that

public void test(){
    methodStart();
    doSomething();
    methodEnd();
}

Copy the code

Add methodStart and methodEnd to the entry and exit of each method you want to monitor, similar to a peg burrow.

Of course, this method of pile insertion has obvious disadvantages:

  • Unable to monitor system methods
  • Apk size increases (more code for each method)

Note:

  • Filter the simple way
  • You only need to monitor the methods executed by the main thread

Fourth, performance optimization

Monitoring the problem is about to start to optimize, in view of the “performance optimization” this point, offering an Ali organized Android performance optimization combat manual, from all aspects of the target product all-round “optimization”, so that the performance of the product is improved from all aspects, I hope you like it.

This “Android360° all-round performance tuning” has 722 pages, 4 big points, 25 small chapters, not only detailed analysis of the underlying principles, but also the practice of big factory.

There is a need for friends, at the end of the free way ~

Chapter one design idea and code quality optimization

The six principles

  • Single responsibility principle
  • Richter’s substitution principle
  • Rely on the inversion principle
  • Interface Isolation Principle

Design pattern: structural pattern

  • The bridge model
  • Adapter mode
  • Decorator mode
  • The proxy pattern
  • Facade (appearance) mode

Design pattern: Create pattern

  • Builder model
  • The singleton pattern
  • Abstract Factory pattern
  • Factory method pattern

The data structure

  • The stack
  • The queue
  • The list
  • The tree

algorithm

  • Sorting algorithm
  • Search algorithm

Chapter 2 program performance optimization

Optimization of startup speed and execution efficiency

  • Cold start and hot start parsing
  • APP start black and white screen solution
  • APP stuck problem analysis and solution
  • StrictMode optimized for startup speed and execution efficiency

Layout detection and optimization

  • Layout hierarchy optimization
  • Excessive rendering

Memory optimization

  • Memory jitter and memory leakage
  • Large memory
  • Bitmap memory optimization
  • Profile memory monitoring tool
  • Mat large object and leak detection
  • Optimize the power consumption
  • Network transmission and data storage optimization Network transmission and data storage optimization
  • APK size optimization
  • Screen adaptation

Optimize the power consumption

  • Doze&Standby
  • Battery Historian
  • JobScheduler
  • WorkManager
  • Network transmission and data storage optimization
  • Google serialization tool Protobuf
  • 7z limit compression

APK size optimization

  • APK thin body
  • Confusion principle of wechat resources

Screen adaptation

  • Principles of adaptation
  • How the screen resolution qualifier fits the smallestWidth qualifier
  • Why choose smallestWidth qualifier adaptation
  • How does it fit with other modules
  • Common Problem Handling

OOM troubleshooting principles

  • Adj Memory management mechanism
  • JVM memory reclamation mechanism and GC algorithm parsing
  • Summary of life cycle related issues
  • Bitmap compression scheme summary

ANR problem resolution

  • AMS system time regulation principle
  • Analysis of program waiting principle
  • ANR problem solution

Crash Monitoring scheme

  • Java layer monitoring scheme
  • Nativie layer monitoring scheme

Chapter three optimization of development efficiency

Git, a distributed version control system

  • This section describes the enterprise efficient continuous integration platform scenario
  • GIT distributed version control system
  • GIT Branch Management

Automated build system Gradle

  • Gradle with Android plugins
  • Gradle is an android gradle plugin
  • Basic use of the Gradle Transform API

Basic use of the Gradle Transform API

  • What is the Transform
  • Usage scenarios of Transform
  • The Transform API learning
  • Type of input

Custom plug-in development

  • Gradle plugin introduction
  • To start preparing
  • practice
  • Customize Gradle plug-ins
  • BuildSrc module mode

The plug-in of actual combat

  • Multi-channel packaging
  • Printing plate automatic nailing

Chapter 4 APP performance optimization practice

startup

  • General process for application startup
  • Cold start and hot start
  • Measurement of start-up speed
  • Startup window optimization
  • Thread optimization
  • System scheduling optimization
  • The GC optimization
  • IO optimization
  • Resource rearrangement
  • Home page layout optimization
  • Class loading optimization
  • Choose the appropriate startup framework
  • Reduce the jump level of your Activity
  • Vendors to optimize
  • The background keep alive

fluency

  • Some tools and routines for performance problem analysis
  • Analyze performance data
  • Performance cases caused by Android platform performance
  • Performance issues caused by the Android App itself
  • Low memory data characteristics and behavior characteristics
  • Application of treasure
  • Analysis of the lag caused by the barrier-free service of IFlytek input method
  • Bytedance: Toutiao graphic details page second practice

The practice of Douyin in APK packet size resource optimization

  • Image compression
  • Webp non-invasive compatibility
  • More DPI optimization
  • Duplicate resource merging
  • ShrinkResource Strict mode
  • Resource confusion (compatible with AAB mode)
  • ARSC thin body

Youku responsive layout technology full analysis

  • Overview of responsive layout technology of Youku APP
  • Youku APP responsive layout landing Android
  • Landing in the distribution scenario
  • Landing in the consumption scene
  • A test scheme for responsive layout of Youku APP

Network optimization

  • Mobile Taobao link optimization in the network
  • Baidu APP in the network depth optimization practice

Mobile Taobao Double 11 performance optimization project revealed

  • Implementation of the one-second rule
  • Startup time and page frame rate increased by 20%
  • Android phones save 50% memory

Autonavi APP full link source code dependency analysis

  • Autonavi APP platform architecture
  • Basic Implementation Principles
  • Project frame
  • Application scenarios and implementation principles

Complete the OOM experience sharing

  • Troubleshooting Memory Leaks
  • Out strategy
  • Memory peak too high
  • Optimization of large map screening

Wechat Android terminal memory optimization practice

  • Activity leak detection
  • Bitmap allocation and collection tracking
  • Native memory leak detection
  • Thread monitoring
  • Memory monitoring

If you want to improve your mobile development performance optimization skills, or are preparing for an interview for a mobile development position, I think this is a great note to miss.

Friends in need just need to like support, and then [Get it for free here】