Skip to content

CatalystInstanceImpl.destroy AsyncTask fails to complete and blocks execution of other AsyncTasks #19895

Closed
@mattijsf

Description

@mattijsf

Environment

Environment:
OS: macOS High Sierra 10.13.5
Node: 8.3.0
Yarn: 1.3.2
npm: 6.0.1
Watchman: 4.9.0
Xcode: Xcode 9.3.1 Build version 9E501
Android Studio: 3.1 AI-173.4819257

Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: 0.55.4 => 0.55.4

Description

During (Android) development I was noticing that sometimes my AsyncTask's were no longer executed. When analyzing the thread dump I noticed that at these times there was always an AsyncTask from React Native's CatalystInstanceImpl alive & running:
https://github.com/facebook/react-native/blob/0.56-stable/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java#L351

"AsyncTask #7@6218" prio=5 tid=0x4f5 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
	  at com.facebook.jni.HybridData$Destructor.deleteNative(HybridData.java:-1)
	  at com.facebook.jni.HybridData$Destructor.destruct(HybridData.java:73)
	  at com.facebook.jni.HybridData.resetNative(HybridData.java:39)
	  - locked <0x1871> (a com.facebook.jni.HybridData)
	  at com.facebook.react.bridge.CatalystInstanceImpl$1$1.run(CatalystInstanceImpl.java:349)
	  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
	  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
	  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
	  at java.lang.Thread.run(Thread.java:764)

Since this task is executed on the global / shared AsyncTask.SERIAL_EXECUTOR other AsyncTask will no longer execute.

It seems like after reloading the bridge this AsyncTask is trying to clean up some (native / c++) resources asynchronously but starts hanging if the bridge is reloaded again while cleaning is still in-progress. I currently related this behavior only to rapid reloading but it might also happen at other moments.

Note that I've only seen it happen when Debugging JS. Without debugging it reloads fine so far.

Reproducible Demo

  • Start an Emulator. I used a Nexus 5X / API 27.
  • react-native init BlockingAsyncTask
  • cd BlockingAsyncTask
  • react-native start
  • open http://localhost:8081/debugger-ui
  • react-native run-android
  • In emulator: CMD+M -> Debug JS Remotely
  • adb logcat | grep CatalystInstanceImpl.destroy

Notice that the adb logcat will contain two lines:

06-25 22:21:29.104 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:21:29.143 30424 30454 D ReactNative: CatalystInstanceImpl.destroy() end

Which is fine. The start and end logs should be balanced.

  • Press R+R again in the emulator:

Again, nicely balanced start and end logs:

06-25 22:27:25.545 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:27:25.552 30424 30791 D ReactNative: CatalystInstanceImpl.destroy() end
  • But now, try to rapidly reload by pressing R+R+R+R:

This time the log shows:

06-25 22:29:03.440 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:29:03.444 30424 30886 D ReactNative: CatalystInstanceImpl.destroy() end
06-25 22:29:03.689 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start

Notice that the last start log has not been balanced with an end log.

  • Any consequent reload now results in only a start log but no end log:
06-25 22:30:01.285 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:04.127 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:15.552 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:20.883 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start

Metadata

Metadata

Assignees

No one assigned

    Labels

    StaleThere has been a lack of activity on this issue and it may be closed soon.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions