background

  • The project is a mix of Flutter and Swift, and the pre-sale page is H5
  • Flutter does not introduce a framework such as Flutter_BOAST, but is a Model of FlutterViewController with one engine
  • The new version is onlineSwift, 5.3Flutter 1.22.32 framework updates

Antecedents feed

After the launch of the new version, frequent crashes occurred, and the crash rate quickly rose to 1%.

However, the stack information was not clear and the specific problem could not be located. It could only be seen that there was a crash on the pre-sale page and it was related to Flutter. KERN_INVALID_ADDRESS indicated that there was a zombie object.

EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000010 libobjC.a. Dylib objc_msgSend + 16 1 Flutter (missing) 2 UIKitCore -[UITextSelection commit] + 256 3 UIKitCore -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) activateSelection] + 48 14 WebKit -[WKContentView(WKInteraction) becomeFirstResponderForWebView] + 352 15 WebKit -[WKWebView(WKViewInternalIOS) becomeFirstResponder] + 144Copy the code

Until the test found that a test machine can be stable reproduce, and provide a reproduce path.

Open the pre-sales page after registration, click left and right to switch the SKU on the pre-sales page, and the skU will collapse.

The body of the

one

At that time, it was 1:30 in the afternoon. I took the test machine and connected it to Xcode for debugging. I went through the replay path provided by the test, but there was no crash

Download a staging package to go through, crash

I tried many times and still got the same result

Based on the Zombie objects given in the crash message, I turned on Zombie detection, but I didn’t get any valid information

Compare the differences between Flutter and Flutter. One is debug mode and the other is release mode

After setting the locally debugged Flutter environment to release mode, it finally reappears

At this time, nearly 3 hours have passed since the debugging of the crash began

two

Again and again, but the crash crashes directly into the main function without any useful information.

At this time, a friend of mine taught me a way to display the current ready-made call stack with bt command, but the information was still very little, which was basically the same as the stack information of crash above.

The problem may arise in1 Flutter (lack of)Here, but I can’t see it. It’s awkward

three

Must appear on the path, there is a phenomenon is registration collapse, login does not collapse

After smoothing out the various differences between the registration and login codes, it remained the same, temporarily deadlocked

At this time, it was already 8:30 p.m., so I temporarily chose to go home from work after every attempt was fruitless

On the way, IT occurred to me that Flutter has three modes: Debug profile and Release. I wonder if I can find anything new by running the Flutter mode

When I got home, I finally tried running in Profile mode after ruling out all the possibilities on the roadSure enough,Flutter (lack of)Turned out to beFlutter -[FlutterTextInputView updateEditingState]At this time, I seem to see the dawn

four

Open Github, search for flutter/ Engine, and see that this method is probably triggered when the keyboard is listening on various things

However, the registered FlutterViewController is closed before opening the pre-sale page, so why does switching skUs on the pre-sale page trigger this method

To verify that this method was called, I set a conditional breakpoint

breakpoint set --func-regex updateEditingState
Copy the code

Sure enough, the breakpoint was triggered when the SKU was switchedStill, there’s not enough useful information. Keep scrolling through Github until you see itThe Flutter source code is used when modifying the delegateassign

Well, that’s a typical interview question. Delegate should be weak

The Developers of Flutter should consider that assign is much less stored than weak

But then, a chain began to form in my mind

There should be a memory leak causing the delegate to be held somewhere

Since we use assign, we hold the delegate’s memory address

The delegate method is called when the pre-sale page triggers a keyboard action when the switch SKU is clicked

But since the delegate itself is freed, the zombie object problem arises

KERN_INVALID_ADDRESS = KERN_INVALID_ADDRESS

five

I quickly checked the code of our flutter and did not see the following method called in the registered captco

FocusScope.of(context).requestFocus(FocusNode());

However, this method is invoked during the login and registration process when you click Next after entering password

After a quick addition of this line and a little debugging, I was ready to celebrate

And yet, it fell apart, but I think that’s the problem

six

I reviewed the Focus related code in the project

Password Focus called the Dispose method of FocusNode in state’s dispose

But focus in the captcha does not call this method

After adding dispose method and testing for 3 times, it was found that the problem was solved

It was half past one in the morning

The latter

After this problem is solved, there are still some things that can be done

  • What is done in Dispose, why will it not be released if it is not called

  • Why does the front end trigger keyboard events when switching SKUs

But these questions are follow-up, irrelevant to this article, so it is no longer superfluous