It’s a bug in Android 11 fixed by google but not deployed yet.
Meanwhile, if you don’t care about calling static and thread_local variables destructors in your lib when program is exiting/library is unloaded, pass the flag
-fno-c++-static-destructors to the compiler. (see long answer for a more granular solution using clang annotations)
I used this flag on my project (not cocos2d) with no issue and lib is loading even faster than before.
Unfortunately this is a performance regression introduced in android 11 (R) by the Google team. The issue is being tracked by google here.
To summarize, when
System.loadLibrary() is called, the system registers a destructor for each of the C++ global variables contained in the loaded library, using __cxa_atexit()
Since Android 11 (R), the implementation of this function in android has changed:
- In Q, __cxa_atexit uses a linked list of chunks, and calls mprotect twice on the single chunk to be modified.
- In R, __cxa_atexit calls mprotect twice on a single contiguous array of handlers. Each array entry is 2 pointers.
This change regressed the performance drastically when they are many C++ global variables which seems to be the case in cocos2d so libraries.
Google has already implemented a fix https://android-review.googlesource.com/c/platform/bionic/+/1464716 but as stated in the issue:
this won’t be in Android 11 until the March QPR at the earliest, and since this isn’t a security issue it won’t be mandatory for OEMs to actually take that patch.
Google Team suggests also some workarounds at the app level by removing or skipping the destructors on global variables:
- For a particular global variable, the [[clang::no_destroy]] attribute skips the destructor call.
- Pass -fno-c++-static-destructors to the compiler to skip the destructors for all static variables. This flag also skips destructors for thread_local variables. If there are thread_local variables with important destructors, those can be annotated with [[clang::always_destroy]] to override the compiler flag.
- Pass -Wexit-time-destructors to the compiler to make it warn on every instance of an exit-time destructor, to highlight where the __cxa_atexit registrations are coming from.
CLICK HERE to find out more related problems solutions.