У меня есть служба, которая должна быть сохранена до тех пор, пока приложение активно. Поэтому в LoginActivity, когда пользователь не вошел в систему, я вызываю stopService, и когда пользователь входит в систему, я запускаю службу, явно просматривая startService.Обнаружена утечка службы до onDestroy
public class LoginActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (accountHelper.isLoggedIn()) {
proceedToMainActivity();
} else if (savedInstanceState == null) {
Fragment fragment = LoginFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.LoginContainer, fragment)
.commit();
}
}
public void proceedToMainActivity() {
final Intent intent = MainActivity.createIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
//...
}
Тогда в других мероприятиях, я связываю в OnStart и отвязать в OnStop, в службе:
@Override
public boolean onUnbind(Intent intent) {
Timber.d("onUnbind: %s", intent);
handler.scheduleStop(KEEP_ALIVE);
return false;
}
Это расписание stopSelf() после keep_alive времени (на данный момент его 500 (полсекунды), но это было нормально для 60000 (одна минута)
Служба уничтожена, когда пользователь уходит из приложения на долгое время и воссоздается успешно, однако после очень короткого времени от onCreate и onBind LeakCanary сообщает об утечке памяти этой службы. Обратите внимание, что ни onUnbind, ни onDestroy не вызывались. LeakCanary дает следующую свалку:
In <app-package>:1.0:7.
* <app-package>.service.SocketService has leaked:
* GC ROOT static android.app.ActivityThread.sCurrentActivityThread
* references android.app.ActivityThread.mServices
* references android.util.ArrayMap.mArray
* references array java.lang.Object[].[1]
* leaks <app-package>.service.SocketService instance
* Retaining: 9.6 KB.
* Reference Key: 525376d3-87b7-4522-9c9a-2d4547bc4f8d
* Device: unknown Android Android SDK built for x86_64 sdk_google_phone_x86_64
* Android Version: 7.1 API: 25 LeakCanary: 1.5 00f37f5
* Durations: watch=5900ms, gc=126ms, heap dump=5628ms, analysis=22007ms
* Details:
* Class android.app.ActivityThread
| static DEBUG_BACKUP = false
| static sPackageManager = [email protected] (0x2ac01350)
| static LOG_AM_ON_STOP_CALLED = 30049
| static MIN_TIME_BETWEEN_GCS = 5000
| static DEBUG_MESSAGES = false
| static $classOverhead = byte[719]@1885346289 (0x706019f1)
| static SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003
| static sCurrentBroadcastIntent = [email protected] (0x70593368)
| static HEAP_COLUMN = [email protected] (0x706d4d98)
| static SERVICE_DONE_EXECUTING_ANON = 0
| static ACTIVITY_THREAD_CHECKIN_VERSION = 4
| static DEBUG_ORDER = false
| static TWO_COUNT_COLUMNS = [email protected] (0x706d4e90)
| static DEBUG_PROVIDER = false
| static TAG = [email protected] (0x706e41d8)
| static DEBUG_CONFIGURATION = false
| static DEBUG_MEMORY_TRIM = false
| static SERVICE_DONE_EXECUTING_STOP = 2
| static DEBUG_SERVICE = false
| static DEBUG_BROADCAST = false
| static HEAP_FULL_COLUMN = [email protected] (0x706d4de8)
| static localLOGV = false
| static sMainThreadHandler = [email protected] (0x2ac02080)
| static THUMBNAIL_FORMAT = [email protected] (0x70593350)
| static REPORT_TO_ACTIVITY = true
| static DEBUG_RESULTS = false
| static DONT_REPORT = 2
| static ONE_COUNT_COLUMN_HEADER = [email protected] (0x706d4ec8)
| static SERVICE_DONE_EXECUTING_START = 1
| static sCurrentActivityThread = [email protected] (0x2ac04100)
| static USER_LEAVING = 1
| static LOG_AM_ON_PAUSE_CALLED = 30021
| static ONE_COUNT_COLUMN = [email protected] (0x706d4e70)
| static LOG_AM_ON_RESUME_CALLED = 30022
* Instance of android.app.ActivityThread
| static DEBUG_BACKUP = false
| static sPackageManager = [email protected] (0x2ac01350)
| static LOG_AM_ON_STOP_CALLED = 30049
| static MIN_TIME_BETWEEN_GCS = 5000
| static DEBUG_MESSAGES = false
| static $classOverhead = byte[719]@1885346289 (0x706019f1)
| static SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003
| static sCurrentBroadcastIntent = [email protected] (0x70593368)
| static HEAP_COLUMN = [email protected] (0x706d4d98)
| static SERVICE_DONE_EXECUTING_ANON = 0
| static ACTIVITY_THREAD_CHECKIN_VERSION = 4
| static DEBUG_ORDER = false
| static TWO_COUNT_COLUMNS = [email protected] (0x706d4e90)
| static DEBUG_PROVIDER = false
| static TAG = [email protected] (0x706e41d8)
| static DEBUG_CONFIGURATION = false
| static DEBUG_MEMORY_TRIM = false
| static SERVICE_DONE_EXECUTING_STOP = 2
| static DEBUG_SERVICE = false
| static DEBUG_BROADCAST = false
| static HEAP_FULL_COLUMN = [email protected] (0x706d4de8)
| static localLOGV = false
| static sMainThreadHandler = [email protected] (0x2ac02080)
| static THUMBNAIL_FORMAT = [email protected] (0x70593350)
| static REPORT_TO_ACTIVITY = true
| static DEBUG_RESULTS = false
| static DONT_REPORT = 2
| static ONE_COUNT_COLUMN_HEADER = [email protected] (0x706d4ec8)
| static SERVICE_DONE_EXECUTING_START = 1
| static sCurrentActivityThread = [email protected] (0x2ac04100)
| static USER_LEAVING = 1
| static LOG_AM_ON_PAUSE_CALLED = 30021
| static ONE_COUNT_COLUMN = [email protected] (0x706d4e70)
| static LOG_AM_ON_RESUME_CALLED = 30022
| mActivities = [email protected] (0x2acf1e20)
| mAllApplications = [email protected] (0x2acf60b8)
| mAppThread = [email protected] (0x2ac02280)
| mAvailThumbnailBitmap = null
| mBackupAgents = [email protected] (0x2acf1e40)
| mBoundApplication = [email protected] (0x2acd0980)
| mCompatConfiguration = [email protected] (0x2acdb7e0)
| mConfiguration = [email protected] (0x2acdb848)
| mCoreSettings = [email protected] (0x2acf60d0)
| mCurDefaultDisplayDpi = 480
| mDensityCompatMode = false
| mGcIdler = [email protected] (0x2aced5d0)
| mGcIdlerScheduled = false
| mH = [email protected] (0x2ac02080)
| mInitialApplication = <app-package>[email protected] (0x2ac752b8)
| mInstrumentation = [email protected] (0x2acac280)
| mInstrumentationAppDir = null
| mInstrumentationLibDir = null
| mInstrumentationPackageName = null
| mInstrumentationSplitAppDirs = null
| mInstrumentedAppDir = null
| mInstrumentedLibDir = null
| mInstrumentedSplitAppDirs = null
| mJitEnabled = true
| mLastAssistStructures = [email protected] (0x2acf60e8)
| mLastSessionId = 0
| mLifecycleSeq = 3
| mLocalProviders = [email protected] (0x2acf1e60)
| mLocalProvidersByName = [email protected] (0x2acf1e80)
| mLooper = [email protected] (0x2ac02060)
| mMainThreadConfig = [email protected] (0x2acdb8b0)
| mNewActivities = null
| mNumVisibleActivities = 1
| mOnPauseListeners = [email protected] (0x2acf1ea0)
| mPackages = [email protected] (0x2acf1ec0)
| mPendingConfiguration = null
| mProfiler = [email protected] (0x2acf6100)
| mProviderMap = [email protected] (0x2acf1ee0)
| mProviderRefCountMap = [email protected] (0x2acf1f00)
| mRelaunchingActivities = [email protected] (0x2acf6118)
| mResourcePackages = [email protected] (0x2acf1f20)
| mResourcesManager = [email protected] (0x2ac50160)
| mServices = [email protected] (0x2acf1f40)
| mSomeActivitiesChanged = true
| mSystemContext = null
| mSystemThread = false
| mThumbnailCanvas = null
| mThumbnailHeight = -1
| mThumbnailWidth = -1
| mUpdatingSystemConfig = false
| shadow$_klass_ = android.app.ActivityThread
| shadow$_monitor_ = 0
* Instance of android.util.ArrayMap
| static DEBUG = false
| static BASE_SIZE = 4
| static EMPTY = [email protected] (0x7059baf0)
| static mBaseCache = java.lang.Object[8]@717433776 (0x2ac32bb0)
| static mBaseCacheSize = 2
| static $classOverhead = byte[453]@1885300129 (0x705f65a1)
| static EMPTY_IMMUTABLE_INTS = int[0]@1884928784 (0x7059bb10)
| static mTwiceBaseCacheSize = 0
| static mTwiceBaseCache = null
| static CACHE_SIZE = 10
| static TAG = [email protected] (0x707a9928)
| mArray = java.lang.Object[8]@718274320 (0x2acfff10)
| mCollections = null
| mHashes = int[4]@718411680 (0x2ad217a0)
| mIdentityHashCode = false
| mSize = 1
| shadow$_klass_ = android.util.ArrayMap
| shadow$_monitor_ = 0
* Array of java.lang.Object[]
| [0] = [email protected] (0x2ad05fe0)
| [1] = <app-package>[email protected] (0x2ad0ddc0)
| [2] = null
| [3] = null
| [4] = null
| [5] = null
| [6] = null
| [7] = null
* Instance of <app-package>.service.SocketService
| static MESSAGE = [email protected] (0x70137f20)
| static TEMP_ID = [email protected] (0x2ad21fc0)
| static $change = null
| static SESSION_ID = [email protected] (0x2ad2aa88)
| static LIMIT = [email protected] (0x70137298)
| static $classOverhead = byte[1708]@718645249 (0x2ad5a801)
| static KEEP_ALIVE = 500
| static USER_CONNECTED = [email protected] (0x2ad436d0)
| static TO_USER_ID = [email protected] (0x2ad21fe0)
| static CHAT_USER_ID = [email protected] (0x2ae8f510)
| static ACCESS_TOKEN = [email protected]80 (0x2ac005d8)
| static ON_SOCKET_CONNECTED = 100
| static serialVersionUID = 0
| static USER_ID = [email protected] (0x7078db90)
| static USER_MESSAGE = [email protected] (0x2ae8f5b0)
| static CHAT_MESSAGE = [email protected] (0x2ae8f4e8)
| static FROM_MESSAGE_ID = [email protected] (0x2aea16d0)
| static MESSAGE_TYPE = [email protected] (0x2ae8f538)
| static USER_TYPING = [email protected] (0x2ae8f5d8)
| static PAY_MESSAGE = [email protected] (0x2ae8f560)
| compositeSubscription = [email protected] (0x2ad02470)
| handler = <app-package>[email protected] (0x2ae48d40)
| messenger = [email protected] (0x2ad02460)
| onChatMessage = <app-package>[email protected] (0x2ad02430)
| onPayMessage = <app-package>[email protected] (0x2ad862f8)
| onUserConnected = <app-package>[email protected] (0x2ad02440)
| onUserMessage = <app-package>[email protected] (0x2ad02420)
| onUserTyping = <app-package>[email protected] (0x2ad86318)
| ready = true
| referenceWatcher = [email protected] (0x2ac75308)
| sessionId = [email protected] (0x2ae20ee0)
| slavicSocketApi = [email protected] (0x2ad02e60)
| socket = [email protected] (0x2ae6cf70)
| storIOSQLite = [email protected]08 (0x2ae6d328)
| taskScheduler = <app-package>[email protected] (0x2ad02450)
| mActivityManager = [email protected] (0x2ac01250)
| mApplication = <app-package>[email protected] (0x2ac752b8)
| mClassName = [email protected] (0x2ad201c8)
| mStartCompatibility = false
| mThread = [email protected] (0x2ac04100)
| mToken = [email protected] (0x2ad05fe0)
| mBase = [email protected] (0x2ae0d3c0)
| shadow$_klass_ = <app-package>.service.SocketService
| shadow$_monitor_ = -2028143957
* Excluded Refs:
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)
Почему сервис обозначен как утечка? UPD: Я удалил явный запуск/остановку службы и задержку остановки из onUnbind, но утечка остается неизменной.
для предотвращения утечек Я хотел бы предложить регистрации/ссылки на службе в методе OnCreate вашего приложения class.eg MediaUploaderService.StartService (это, MediaUploaderService.START_APP_START), то в вашей службе в onStartCommand методы убедитесь, что вы имеете возвращенное обслуживание. START_STICK, который сообщает ОС, чтобы воссоздать службу после того, как у нее достаточно памяти, и снова вызовите onStartCommand() с нулевым намерением. Это должно помочь решить проблему утечки. См. Также эту ссылку. http://stackoverflow.com/questions/9093271/start-sticky-and-start-not-sticky – Zidane
@ Zidane, это не совсем то, что я искал. На данный момент я удалил явное начало/остановку и задержку остановки службы в onUnbind, так что служба будет уничтожена, если никакая активность не будет привязана к ней быстро. Но утечка остается, возможно, это необходимая утечка для связанных служб. –