처리 방법 :java.util.current.시간 초과예외: Android.os.BinderProxy.finalize()가 10초 오류 후 시간 초과되었습니까?
우리는 많은 것을 보고 있습니다.TimeoutExceptions
GcWatcher.finalize, BinderProxy.finalize
,그리고.PlainSocketImpl.finalize
중 % 이 Android3.90% 에서 발생합니다.3에서 발생합니다.우리는 현장의 사용자들로부터 Crittercism으로부터 이것에 대한 보고를 받고 있습니다.
" 류는다변음니다입형의오: "com.android.internal.BinderInternal$GcWatcher.finalize() timed out after 10 seconds
"
java.util.concurrent.TimeoutException: android.os.BinderProxy.finalize() timed out after 10 seconds
at android.os.BinderProxy.destroy(Native Method)
at android.os.BinderProxy.finalize(Binder.java:459)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:187)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:170)
at java.lang.Thread.run(Thread.java:841)
지금까지 우리는 집안의 문제를 재현하거나 무엇이 문제를 일으켰는지 알아내는 데 전혀 운이 없었습니다.
무엇이 이것을 유발할 수 있는지 아십니까?이것을 디버그하고 앱의 어떤 부분이 이것을 유발하는지 알아내는 방법을 알고 있습니까?문제를 밝히는 것은 무엇이든 도움이 됩니다.
추가 스택 추적:
1 android.os.BinderProxy.destroy
2 android.os.BinderProxy.finalize Binder.java, line 482
3 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187
4 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170
5 java.lang.Thread.run Thread.java, line 841
2
1 java.lang.Object.wait
2 java.lang.Object.wait Object.java, line 401
3 java.lang.ref.ReferenceQueue.remove ReferenceQueue.java, line 102
4 java.lang.ref.ReferenceQueue.remove ReferenceQueue.java, line 73
5 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170
6 java.lang.Thread.run
3
1 java.util.HashMap.newKeyIterator HashMap.java, line 907
2 java.util.HashMap$KeySet.iterator HashMap.java, line 913
3 java.util.HashSet.iterator HashSet.java, line 161
4 java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers ThreadPoolExecutor.java, line 755
5 java.util.concurrent.ThreadPoolExecutor.interruptIdleWorkers ThreadPoolExecutor.java, line 778
6 java.util.concurrent.ThreadPoolExecutor.shutdown ThreadPoolExecutor.java, line 1357
7 java.util.concurrent.ThreadPoolExecutor.finalize ThreadPoolExecutor.java, line 1443
8 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187
9 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170
10 java.lang.Thread.run
4
1 com.android.internal.os.BinderInternal$GcWatcher.finalize BinderInternal.java, line 47
2 java.lang.Daemons$FinalizerDaemon.doFinalize Daemons.java, line 187
3 java.lang.Daemons$FinalizerDaemon.run Daemons.java, line 170
4 java.lang.Thread.run
완전 공개 - 저는 TLV DroidCon에서 이전에 언급된 강연의 저자입니다.
저는 많은 Android 애플리케이션에서 이 문제를 검토하고, 이 문제를 접한 다른 개발자들과 논의할 기회가 있었습니다. 그리고 우리는 모두 같은 지점에 도달했습니다. 이 문제는 피할 수 없고, 최소화될 뿐입니다.
Android Garbage Collector 코드의 기본 구현을 자세히 살펴봄으로써 이 예외가 발생하는 이유와 가능한 원인을 더 잘 이해할 수 있었습니다.저는 심지어 실험 중에 가능한 근본 원인을 발견했습니다.
문제의 근본 원인은 잠시 동안 장치가 "휴면 상태"로 전환된다는 것입니다. 즉, OS가 대부분의 User Land 프로세스를 잠시 중단하고 화면을 꺼 CPU 주기를 줄이는 등의 방법으로 배터리 소모를 줄이기로 결정했다는 것입니다.이 방법은 프로세스가 실행 중에 일시 중지되는 Linux 시스템 수준에서 수행됩니다.이 문제는 정상적인 응용 프로그램 실행 중에 언제든지 발생할 수 있지만 컨텍스트 전환이 커널 수준에서 수행되기 때문에 네이티브 시스템 호출에서 중지됩니다.그래서 - 이것이 Dalvik GC가 이야기에 참여하는 부분입니다.
AOSP 사이트의 Dalvik 프로젝트에서 구현된 Dalvik GC 코드는 복잡한 코드 조각이 아닙니다.기본적인 작동 방식은 제 DroidCon 슬라이드에 나와 있습니다.제가 다루지 않은 것은 기본 GC 루프입니다. 수집기에 완료(및 파기)할 개체 목록이 있는 지점입니다.베이스의 루프 로직은 다음과 같이 단순화할 수 있습니다.
- 가지고 가다
starting_timestamp
, - 릴리스할 개체 목록에 대한 개체 제거,
- object - 릴스개체리 -
finalize()
네이티브라고 부릅니다.destroy()
경우, 파일 이름을 지정 - 가지고 가다
end_timestamp
, - 계산하다, 계산하다, 계산하다, 계산하다, 계산하다, 계산함
end_timestamp - starting_timestamp
및 초과 및 하 초 값 초 과 10 비 - - - .
java.util.concurrent.TimeoutException
그리고 그 과정을 죽입니다.
이제 다음 시나리오를 생각해 보겠습니다.
애플리케이션은 작업을 수행하면서 실행됩니다.
이것은 사용자 대면 응용 프로그램이 아니라 백그라운드에서 실행됩니다.
이 백그라운드 작업 중에 개체가 생성되고 사용되며 메모리를 해제하기 위해 수집해야 합니다.
WakeLock은 배터리에 악영향을 미치며 불필요한 것처럼 보이기 때문에 응용 프로그램은 WakeLock을 사용하지 않습니다.
이것은 애플리케이션이 GC를 때때로 호출한다는 것을 의미합니다.
일반적으로 GC 실행은 문제 없이 완료됩니다.
때때로(매우 드물게) 시스템이 GC 실행 도중에 절전 모드로 전환합니다.
애플리케이션을 충분히 오래 실행하고 Dalvik 메모리 로그를 자세히 모니터링하면 이러한 현상이 발생합니다.
- GC합니다 - 장치가 할 수 , " - " GC"를 합니다. 장치가 실행을 시작할 수 있습니다.start_stamp
그리고 호텔에서 잠을 잡니다.destroy()
시스템 개체에 대한 네이티브 호출입니다.
달리기를 하면, 시템이깨재실개면하을행어나스,▁▁the,destroy()
이고, 은 끝것이고은다, 음날은▁will입니다.end_stamp
시간이 소요될 것입니다.destroy()
통화 + 수면 시간을 누릅니다.
), 수면시길경우초이(10초 이상),java.util.concurrent.TimeoutException
던져질 것입니다.
저는 이것을 분석 파이썬 스크립트에서 생성된 그래프에서 보았습니다 - 제가 모니터링하는 앱뿐만 아니라 안드로이드 시스템 애플리케이션용입니다.
로그를 충분히 수집하면 최종적으로 로그를 볼 수 있습니다.
결론:
이 문제는 피할 수 없습니다. 앱이 백그라운드에서 실행되면 발생합니다.
WakeLock을 사용하여 장치가 절전 모드로 전환되는 것을 방지할 수 있습니다. 하지만 이는 완전히 다른 이야기이고, 새로운 골칫거리이며, 다른 사기극에 대한 이야기일 수도 있습니다.
GC 호출을 줄임으로써 문제를 최소화할 수 있습니다. 시나리오의 가능성을 낮춥니다(슬라이드에 팁이 있음).
저는 아직 새로운 세대 압축 기능을 자랑하는 Dalvik 2(일명 ART) GC 코드를 검토할 기회가 없었고 Android Rollipop에 대한 실험을 수행할 기회가 없었습니다.
2015년 7월 5일 추가:
이 충돌 유형에 대한 충돌 보고서 집계를 검토한 결과, Android OS 5.0+ 버전의 이러한 충돌이 이 충돌 유형의 0.5%만 차지하는 것으로 보입니다.즉, ART GC 변경으로 인해 이러한 충돌 빈도가 감소했습니다.
2016년 6월 1일 추가:
Android 프로젝트는 GC가 Dalvik 2.0(일명 ART)에서 어떻게 작동하는지에 대한 많은 정보를 추가한 것 같습니다.
여기에서 ART 가비지 컬렉션 디버깅에 대해 읽을 수 있습니다.
또한 앱의 GC 동작에 대한 정보를 얻기 위한 몇 가지 도구에 대해서도 설명합니다.
SIGQUIT를 앱 프로세스로 전송하면 본질적으로 ANR이 발생하고 분석을 위해 애플리케이션 상태를 로그 파일에 덤프합니다.
우리는 Crashlytics를 사용하여 앱 전체에서 이러한 현상을 지속적으로 볼 수 있습니다.충돌은 일반적으로 플랫폼 코드에서 훨씬 아래에서 발생합니다.소량의 표본 추출:
안드로이드. 안드로이드.커서 창입니다.finalize(종료) 10초 후에 시간 초과됨
java.java.regex.Matcher.finalize()가 10초 후에 시간 초과됨
안드로이드. 안드로이드.비트맵$BitmapFinalizer.finalize()가 10초 후 시간 초과됨
기관. 기관. 기관. 기관. 기관. 기관. 기관. 기관. 기관. 기관. 기관.SingleClientConnManager.finalize()가 10초 후 시간 초과됨
java.java.current.ThreadPoolExecutor.finalize()가 10초 후에 시간 초과됨
안드로이드.os.BinderProxy.finalize()가 10초 후에 시간 초과됨
안드로이드. 안드로이드.Path.finalize()가 10초 후에 시간 초과됨
이러한 현상이 발생하는 장치는 압도적으로 (단, 독점적인 것은 아님) 삼성에서 제조한 장치입니다.이는 대부분의 사용자가 삼성 기기를 사용하고 있다는 것을 의미할 수 있습니다. 또는 삼성 기기에 문제가 있다는 것을 나타낼 수도 있습니다.잘 모르겠어요.
이것이 당신의 질문에 대한 답이 아니라고 생각합니다만, 저는 이것이 상당히 일반적인 것처럼 보이며 당신의 애플리케이션에 특정되지 않는다는 것을 강조하고 싶습니다.
이 문제에 대한 슬라이드를 몇 개 찾았습니다.
이 슬라이드에서 저자는 힙에 많은 개체나 큰 개체가 있으면 GC에 문제가 있는 것 같다고 말합니다.슬라이드에는 샘플 앱에 대한 참조와 이 문제를 분석하기 위한 파이썬 스크립트도 포함되어 있습니다.
https://github.com/oba2cat3/GCTest
https://github.com/oba2cat3/logcat2memorygraph
게다가 이쪽의 댓글 #3에서 힌트를 찾았습니다: https://code.google.com/p/android/issues/detail?id=53418#c3
여기 이 문제를 해결하기 위한 didi의 효과적인 해결책이 있습니다. 이 버그는 매우 흔하고 원인을 찾기가 어렵기 때문에 시스템 문제에 더 가깝습니다. 왜 우리는 그것을 직접 무시할 수 없습니까?물론 무시할 수 있습니다. 샘플 코드는 다음과 같습니다.
final Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler =
Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
if (t.getName().equals("FinalizerWatchdogDaemon") && e instanceof TimeoutException) {
} else {
defaultUncaughtExceptionHandler.uncaughtException(t, e);
}
}
});
응용 프로그램은 특수 기본 탐지되지 않은 예외 처리기를 설정하여 시스템이 제공한 기본 동작을 이미 수락하는 스레드에 대해 탐지되지 않은 예외를 처리하는 방식을 변경할 수 있습니다. 때TimeoutException
는 라는 이스던서집에다니레드의름라는 이름의 .FinalizerWatchdogDaemon
이 특수 처리기는 처리기 체인을 차단하고 시스템 처리기는 호출되지 않으므로 충돌을 방지합니다.
연습을 통해, 다른 나쁜 영향은 발견되지 않았습니다.GC 시스템은 여전히 작동 중이며, CPU 사용량이 감소함에 따라 시간 초과가 완화됩니다.
자세한 내용은 https://mp.weixin.qq.com/s/uFcFYO2GtWWiblotem2bGg 를 참조하십시오.
우리는 그 문제를 중단함으로써 해결했습니다.FinalizerWatchdogDaemon
.
public static void fix() {
try {
Class clazz = Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");
Method method = clazz.getSuperclass().getDeclaredMethod("stop");
method.setAccessible(true);
Field field = clazz.getDeclaredField("INSTANCE");
field.setAccessible(true);
method.invoke(field.get(null));
}
catch (Throwable e) {
e.printStackTrace();
}
}
응용 프로그램의 라이프사이클에 있는 메서드를 다음과 같이 호출할 수 있습니다.attachBaseContext()
같은 이유로 문제를 해결하기 위해 전화기의 제조업체를 지정할 수도 있습니다. 사용자에게 달려 있습니다.
브로드캐스트 수신기가 10초 후에 시간 초과됩니다.브로드캐스트 수신기 및 4.3에서 비동기 호출(잘못됨)을 수행하면 실제로 탐지할 수 있습니다.
이 때 장치가 일부 메모리에 대해 질식할 수 있다는 것이 항상 사실입니다(일반적으로 GC가 트리거될 가능성이 가장 높은 이유).
앞에서 거의 모든 저자가 언급했듯이 앱이 백그라운드에 있는 동안 Android가 GC를 실행하려고 할 때 이 문제가 표면화됩니다.우리가 관찰한 대부분의 경우, 사용자는 화면을 잠그면서 앱을 일시 중지했습니다.이는 응용 프로그램 어딘가에서 메모리 누수가 발생했거나 장치가 이미 로드되었음을 나타낼 수도 있습니다.따라서 이를 최소화하는 유일한 합법적인 방법은 다음과 같습니다.
- 메모리 누수가 없는지 확인합니다.
- 일반적으로 앱의 메모리 설치 공간을 줄입니다.
try {
Class<?> c = Class.forName("java.lang.Daemons");
Field maxField = c.getDeclaredField("MAX_FINALIZE_NANOS");
maxField.setAccessible(true);
maxField.set(null, Long.MAX_VALUE);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
최종판대기열이 너무 길 수 있습니다.
저는 자바가 GC를 요구할 수도 있다고 생각합니다.Finalize() & GC를 누릅니다.ReRegisterForFinalize(): 사용자가 최종 대기열 길이를 명시적으로 줄일 수 있습니다.
JVM의 소스 코드를 사용할 수 있다면 안드로이드 ROM 제조기와 같은 이러한 방법을 직접 구현할 수 있습니다.
안드로이드 런타임 버그인 것 같습니다.개별 스레드에서 실행되고 스택 추적의 현재 프레임에 없는 개체에 대해 finalize() 메서드를 호출하는 finalizer가 있는 것 같습니다.예를 들어 다음 코드(이 문제를 확인하기 위해 만든 코드)는 충돌로 끝납니다.
final 메서드에서 무언가를 수행하는 커서(예: SqlCipher, close()를 수행하여 현재 사용 중인 데이터베이스에 잠급니다.)
private static class MyCur extends MatrixCursor {
public MyCur(String[] columnNames) {
super(columnNames);
}
@Override
protected void finalize() {
super.finalize();
try {
for (int i = 0; i < 1000; i++)
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
그리고 커서를 열어 긴 실행 작업을 수행합니다.
for (int i = 0; i < 7; i++) {
new Thread(new Runnable() {
@Override
public void run() {
MyCur cur = null;
try {
cur = new MyCur(new String[]{});
longRun();
} finally {
cur.close();
}
}
private void longRun() {
try {
for (int i = 0; i < 1000; i++)
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
이로 인해 다음과 같은 오류가 발생합니다.
FATAL EXCEPTION: FinalizerWatchdogDaemon
Process: la.la.land, PID: 29206
java.util.concurrent.TimeoutException: MyCur.finalize() timed out after 10 seconds
at java.lang.Thread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:371)
at java.lang.Thread.sleep(Thread.java:313)
at MyCur.finalize(MessageList.java:1791)
at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:222)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:209)
at java.lang.Thread.run(Thread.java:762)
SqlCipher를 사용하는 프로덕션 변형은 매우 유사합니다.
12-21 15:40:31.668: E/EH(32131): android.content.ContentResolver$CursorWrapperInner.finalize() timed out after 10 seconds
12-21 15:40:31.668: E/EH(32131): java.util.concurrent.TimeoutException: android.content.ContentResolver$CursorWrapperInner.finalize() timed out after 10 seconds
12-21 15:40:31.668: E/EH(32131): at java.lang.Object.wait(Native Method)
12-21 15:40:31.668: E/EH(32131): at java.lang.Thread.parkFor$(Thread.java:2128)
12-21 15:40:31.668: E/EH(32131): at sun.misc.Unsafe.park(Unsafe.java:325)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.LockSupport.park(LockSupport.java:161)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:840)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:873)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1197)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
12-21 15:40:31.668: E/EH(32131): at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
12-21 15:40:31.668: E/EH(32131): at net.sqlcipher.database.SQLiteDatabase.lock(SourceFile:518)
12-21 15:40:31.668: E/EH(32131): at net.sqlcipher.database.SQLiteProgram.close(SourceFile:294)
12-21 15:40:31.668: E/EH(32131): at net.sqlcipher.database.SQLiteQuery.close(SourceFile:136)
12-21 15:40:31.668: E/EH(32131): at net.sqlcipher.database.SQLiteCursor.close(SourceFile:510)
12-21 15:40:31.668: E/EH(32131): at android.database.CursorWrapper.close(CursorWrapper.java:50)
12-21 15:40:31.668: E/EH(32131): at android.database.CursorWrapper.close(CursorWrapper.java:50)
12-21 15:40:31.668: E/EH(32131): at android.content.ContentResolver$CursorWrapperInner.close(ContentResolver.java:2746)
12-21 15:40:31.668: E/EH(32131): at android.content.ContentResolver$CursorWrapperInner.finalize(ContentResolver.java:2757)
12-21 15:40:31.668: E/EH(32131): at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:222)
12-21 15:40:31.668: E/EH(32131): at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:209)
12-21 15:40:31.668: E/EH(32131): at java.lang.Thread.run(Thread.java:762)
다시 시작: 최대한 빨리 커서를 닫습니다.적어도 문제가 발견된 Android 7이 탑재된 Samsung S8에서.
생성한 클래스(즉, Android에 포함되지 않음)의 경우 충돌을 완전히 방지할 수 있습니다.
구현하는 모든 클래스finalize()
@oba가 설명한 것처럼 충돌할 수 있는 불가피한 가능성이 있습니다.따라서 마무리 도구를 사용하여 정리를 수행하는 대신PhantomReferenceQueue
.
예제를 보려면 React Native에서 구현을 확인하십시오. https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/jni/DestructorThread.java
언급URL : https://stackoverflow.com/questions/24021609/how-to-handle-java-util-concurrent-timeoutexception-android-os-binderproxy-fin
'programing' 카테고리의 다른 글
Oracle 트리거에 임의 매개 변수를 보내는 방법은 무엇입니까? (0) | 2023.08.19 |
---|---|
Capistrano를 사용하여 다른 깃 분기에서 배치 (0) | 2023.08.19 |
SQL 네트워크 인터페이스, 오류: 26 - 지정된 서버/인스턴스를 찾는 중 오류 발생 (0) | 2023.08.19 |
CSV 윈도우즈 PowerShell에 열 추가 (0) | 2023.08.19 |
MySQL DB를 사용한 Django 날짜 필드 (0) | 2023.08.19 |