Unity ANR'leri çeşitli nedenlerle oluşur. En yaygın ANR'ler, Android ve Unity bileşenlerinin yanlış kullanımından ve aralarındaki yanlış iletişimden kaynaklanır.
Web Görünümü
WebView
, web sayfalarını görüntüleyen bir Android sınıfıdır. Üçüncü taraf SDK'ları (ör. reklamlar), WebView
kullanarak UnityPlayerActivity
dışındaki etkinliklerde dinamik web içeriği gösterir. ANR'ler, üçüncü taraf SDK'ları WebView
öğesini yanlış kullandığında meydana gelir.
Yığın izi
ANR'nin nedenini anlamak için ilk başvuracağınız yer yığın izidir.
/data/app/~~p-0ksfCD6bF6Sdq6kpVePg==/com.google.android.webview-5YQZOqKbbqp-uoLY6WYnTw==/base.apk!libmonochrome.so
at J.N.Mhc_M_H$ (Native method)
at org.chromium.components.viz.service.frame_sinks.ExternalBeginFrameSourceAndroid.doFrame (chromium-TrichromeWebViewGoogle.aab-stable-579013831:60)
at android.view.Choreographer$CallbackRecord.run (Choreographer.java:1054)
at android.view.Choreographer.doCallbacks (Choreographer.java:878)
at android.view.Choreographer.doFrame (Choreographer.java:807)
at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:1041)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:223)
at android.app.ActivityThread.main (ActivityThread.java:7721)
at java.lang.reflect.Method.invoke (Native method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:952)
Şekil 1. Futex beklemesinden kaynaklanan ANR yığın izlemesi.
Neden
Şu ana kadar bu sorunun temel nedeni netleşmemiştir. Olası nedenlerden bazıları şunlardır:
- Kötü reklam uygulaması.
- Kullanıcı, uygulamayı otomatik olarak güncellememeyi tercih etmiş olabileceğinden
WebView
'nın eski bir sürümü - Sistem kaynaklarının (CPU, GPU vb.) yüksek kullanımı, bu da çok fazla profil oluşturmayı gerektirebilir.
- Shader derlemesi kilitleniyor. Bu durum, içerikte uyumsuz bir shader olduğu veya kullanıcının eski bir
WebView
sürümü yüklü olduğu anlamına gelebilir.
Çözüm
WebView
'nın ana iş parçacığını engellemesine hangi içerik türünün neden olduğunu daraltmak için bir web sayfası her yüklendiğinde, görüntülendiğinde veya kapatıldığında oyununuza günlükler ekleyin.- Backtrace veya Crashlytics raporlama hizmetlerini kullanabilirsiniz.
- Ardından, verileri analiz edip sorunu bulduktan sonra sorunlu reklam sağlayıcıları devre dışı bırakmayı deneyin.
- Sorunun bellekle ilgili olmadığından emin olmak için bellek günlüklerini ekleyin.
- Kullanıcıyı Google Play'den
WebView
uygulamasını güncellemesi konusunda uyarın. Android 5.0 (API düzeyi 21) ve sonraki sürümlerdeWebView
, APK'ya taşındı. Bu nedenle, Android platformundan ayrı olarak güncellenebilir. Bir cihazda hangiWebView
sürümünün kullanıldığını görmek için Ayarlar > Uygulamalar > Android System WebView'a gidin ve sayfanın alt kısmındaki sürüme bakın.

WebView
sürümünü kontrol edin.Unity'de duraklatma
UnityPlayerActivity
, onPause()
araması aldığında aşağıdaki işlem zinciri başlar:
UnityPlayerActivity
, etkinliğin duraklatıldığını Unity çalışma zamanı motoruna bildirir.- Unity,
MonoBehaviour
etkinliğini uygulayan herOnApplicationPause
öğesini çağırır. - Unity, ses oynatma, oluşturma, oyun döngüsü ve animasyon gibi bileşenlerini ve modüllerini durdurur.
- Hem
Unity Android Player
(UAP) hem de motorun senkronize olduğundan emin olmak için UAP, motorun durmasını 4 saniye bekler. - Bu işlem 5 saniyeden uzun sürerse sistem ANR'yi tetikler.
Yığın izi
"main" tid=1 Timed Waiting
jdk.internal.misc.Unsafe.park (Native method)
java.util.concurrent.locks.LockSupport.parkNanos (LockSupport.java:234)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos (AbstractQueuedSynchronizer.java:1079)
java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos (AbstractQueuedSynchronizer.java:1369)
java.util.concurrent.Semaphore.tryAcquire (Semaphore.java:415)
com.unity3d.player.UnityPlayer.pauseUnity (UnityPlayer.java:833)
com.unity3d.player.UnityPlayer.pause (UnityPlayer.java:796)
com.unity3d.player.UnityPlayerActivity.onPause (UnityPlayerActivity.java:117)
android.app.Activity.performPause (Activity.java:8517)
android.app.Instrumentation.callActivityOnPause (Instrumentation.java:1618)
android.app.ActivityThread.performPauseActivityIfNeeded (ActivityThread.java:5061)
android.app.ActivityThread.performPauseActivity (ActivityThread.java:5022)
android.app.ActivityThread.handlePauseActivity (ActivityThread.java:4974)
android.app.servertransaction.PauseActivityItem.execute (PauseActivityItem.java:48)
android.app.servertransaction.ActivityTransactionItem.execute (ActivityTransactionItem.java:45)
android.app.servertransaction.TransactionExecutor.executeLifecycleState (TransactionExecutor.java:179)
android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:97)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2303)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loopOnce (Looper.java:201)
android.os.Looper.loop (Looper.java:288)
android.app.ActivityThread.main (ActivityThread.java:7884)
java.lang.reflect.Method.invoke (Native method)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:936)
3.Şekil Hiç serbest bırakılmayan bir semaforun neden olduğu ANR.
Çözüm
C# oyun kodunuzun, duraklatma veya devam ettirme etkinliği sırasında yürütmeyi tamamlamasının çok uzun sürmediğinden emin olun.
- Oyununuzun profilini oluşturun ve
OnApplicationPause
işleminin maliyetli olup olmadığını kontrol edin.Stopwatch
kullanabilirsiniz. - G/Ç işlemlerinden veya senkron ağ isteklerinden kaçının.
Task
simgesini kullanarak işlemleri başka birThread
'ye taşıyın. Unity 2023.1, C#async
veawait
anahtar kelimelerini kullanarak basitleştirilmiş bir eşzamansız programlama modelini destekler.
UnitySendMessage engellendi
Java Unity eklentileri ve SDK'ları, JNI kullanarak C# oyun katmanına veri gönderir. Ancak bu iletişim, mutex gibi yerel bir senkronizasyon rutini nedeniyle ana iş parçacığını engelleyebilir ve kilit çekişmesi nedeniyle ANR'ye neden olabilir.
Yığın izi
Şekil 4'teki ANR, bir Java eklentisi tarafından çağrılan C# kodundaki uzun bir işlemden kaynaklanmıştır. Unity motoru, doğru yürütmeyi sağlamak için Non-Priority Inheritance mutex kullanır.
libc.so NonPI::MutexLockWithTimeout(pthread_mutex_internal_t*, bool, timespec const*) + 604
com.unity3d.player.UnityPlayer.nativeUnitySendMessage (Native method)
com.unity3d.player.UnityPlayer.UnitySendMessage (UnityPlayer.java:665)
Şekil 4. Kilit çekişmesinden kaynaklanan ANR.
Neden
Sorun, uygulama devam ettirildiğinde birden fazla mesaj gönderilmesidir. Oyun arka plandayken gönderilemedikleri için mesajlar sıraya alınır. Uygulama devam ettirildiğinde tüm mesajlar aynı anda gönderilir.
Duraklatma döneminde genellikle oyununuzun bilgilerini sunucuda saklarsınız. Örneğin, oyunun devam etmesi durumunda oyuncunun aynı yere dönebilmesi için oyuncunun oyundaki konumunu kaydedersiniz.
Bu iş yükü, kendi iş yükünü oluşturan diğer üçüncü taraf kodlarıyla birlikte cihazın kaynaklarını, özellikle de ana iş parçacığını aşırı yükleyebilir. Ana iş parçacığı, uygulamanın kullanıcı arayüzünü çalıştırır ve genellikle ANR'lerin ana konumudur. Bu nedenle, ana iş parçacığına eklenen her iş yükü ANR olasılığını artırır.
Çözüm
Uygulama duraklatıldığında tüm kod işlemlerinizin gerekli olduğundan emin olun veya kullanıcının durumunu yerel cihaz belleğinize kaydetmeyi deneyin. Ayrıca, bu işlemleri duraklatma dönemi dışında da tamamlayıp tamamlayamayacağınızı kontrol edin.
Birkaç yaklaşım:
- Mesajı işleyen C# işlemini ana iş parçacığı dışındaki bir iş parçacığına taşıyın.
- Kodunuz Unity'nin ana iş parçacığı bağlamına bağlı değilse iletişim için mesaj yerine
Task
kullanın.
- Kodunuz Unity'nin ana iş parçacığı bağlamına bağlı değilse iletişim için mesaj yerine
- Oyun duraklatıldığında eklentinizden birden fazla mesaj göndermeyin.
- Oyun arka plandayken motor mesaj gönderemez.
- Yalnızca oyun işlevselliğinizi etkilemiyorsa son veri durumunu oyununuza gönderin.
Yükleme yönlendireni
Play Install Referrer, bir kullanıcı bir reklamı her tıkladığında Play Store'a gönderilen benzersiz bir dizedir. Android'e özgü bir reklam izleme tanımlayıcısıdır. Yüklendikten sonra uygulama, yükleme yönlendireni ilişkilendirme iş ortağına gönderir. Bu iş ortağı, kaynağı yüklemeyle eşleştirir (dönüşümü ilişkilendirir).
Yığın izi
Şekil 5'te, yükleme ilişkilendirmesini almak için Facebook SDK'sını kullanan bir oyundan alınan ANR yığın izi gösterilmektedir.

Neden
ANR, yavaş bir bağlayıcı çağrısından kaynaklanıyordu. Ancak SDK kaynak koduna erişim olmadan temel neden belirlenemez.
Çözüm
Bu tür sorunları çözmek için SDK geliştiricisiyle iletişim kurmak veya olası bir çözüm için internette çok fazla arama yapmak, SDK'nın daha yeni bir sürümünün ANR'yi diğer kullanıcılar için çözüp çözmediğini kontrol etmek, hatta küçük bir dağıtım stratejisiyle denemeler yapmak gerekir.
Google, Google Play uygulamalarındaki kullanım verilerini kod algılama yoluyla toplanan bilgilerle birleştirerek SDK Dizini sayfası sunar. Bu sayfa, SDK'ları uygulamanıza ekleme, kaldırma veya kullanmaya devam etme konusunda karar verirken yararlanabileceğiniz özellikler ve sinyaller sağlar.
Ek kaynaklar
ANR'ler hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklara göz atın:
- ANR'lerde hata ayıklama - Android oyun geliştirme
- ANR'ler: Uygulama kalitesi