题目
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
提示:
-
1 <= n <= 9
- 皇后彼此不能相互攻击,也就是说:任何两个皇后都不能处于同一条横行、纵行或斜线上。
Scope代表作用域,不同作用域下定义两个一样的对象声明,最终会产生不同的对象。
通过Kotlin的委托、扩展、DSL等语法,可以把对象的注入获取封装成简洁、无感知的形式。
其他所有的功能扩展,都是以上面的基本流程展开的,有了主线逻辑,其他都很好懂。
https://square.github.io/leakcanary/getting_started/
在gradle配置中引入依赖后就自动启用了LeakCanary
LeakCanary 会自动检测下列对象的泄露:
手动观测一个对象的泄露,通过以下方法调用:AppWatcher.objectWatcher.watch(myDetachedView, “View was detached”)
因为在AndroidManifest里注册了名为AppWatcherInstaller$LeakCanaryProcess的ContentProvider,App启动时会自动调用ContentProvider的onCreate()方法
在这里会调用AppWatcher.manualInstall(application), 这就是LeakCanary启动的入口。
ContentProvider.onCreate()调用时机是:
Application.attachBaseContext() > ContentProvider.onCreate() ->Application.onCreate()
主要是调用了
通过以fragment为容器,创建一个ViewModelProvider实例,再创建一个ViewModelClearedWatcher实例,ViewModelClearedWatcher是一个ViewModel;
构造ViewModelClearedWatcher时,会获取到以fragment为容器的所有的ViewModel实例,然后在ViewModelClearedWatcher的onCleared()中objectWatcher.watch()观察fragment下的所有的ViewModel实例,检查是否有ViewModel实例发生内存泄漏
会调用InternalLeakCanary.invoke(application)
创建一个持有要检测对象的WeakReference,然后主动触发一次GC,如果这个对象能被回收,则WeakReference.get()会为null,并且这个WeakReference实例会被放到创建WeakReference对象时给构造函数传的ReferenceQueue中。
WeakReference的特点就是,只要发生垃圾回收,WeakReference持有的对象引用就为null,并且ReferenceQueue中会存入这个WeakReference;没有发生垃圾回收,ReferenceQueue中不会存入WeakReference对象。
如果主动触发GC后,ReferenceQueue中没有监测的对象对应的WeakReference,说明该对象发生了内存泄漏。
创建了一个KeyedWeakReference对象,存入一个名为watchedObjects,map,key就是UUID.randomUUID()随机生成的,唯一标识watchedObject,value类型是KeyedWeakReference
主线程中延迟一段时间(AppWatcher.config.watchDurationMillis,默认为5秒)后,然后调用moveToRetained(key)
先通过removeWeaklyReachableObjects()清理掉watchedObjects这个map中已经被垃圾回收的对象
如果再发现map里的这个KeyedWeakReference对象还存在,就标记其为retained状态,具体会赋值KeyedWeakReference的retainedUptimeMillis为当前时间,记录下被认为是retained状态时发生的时间;也就是认为没有被垃圾回收,这里其实有两种情况,一种是垃圾回收还没有发生,一种是垃圾回收发生了但是没有回收掉。
再通知所有的OnObjectRetainedListener有对象没有被回收
KeyedWeakReference是WeakReference子类,多了4个属性
在watch()和moveToRetained()的一开始都会调用removeWeaklyReachableObjects()
如果ReferenceQueue存在了某个Reference,说明已经被垃圾回收了,不需要监测内存泄漏了,从watchedObjects中移除这个Reference对象
每次从ReferenceQueue调用poll()方法,取出元素就是去除了队首元素
InternalLeakCanary实现了OnObjectRetainedListener接口,在OnObjectRetainedListener.onObjectRetained()被调用时调用了scheduleRetainedObjectCheck(),然后又会调用heapDumpTrigger.scheduleRetainedObjectCheck() -> HeapDumpTrigger.checkRetainedObjects()
延迟时间为0,立刻调用
主要就是一件事:
在App可见或不可见时,调用HeapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
App可见的定义是:有Activity走了onStart()但还没有走onStop()
App不可见的定义是:所有Activity走过onStop()
在App不可见时,调用HeapDumpTrigger.scheduleRetainedObjectCheck() -> HeapDumpTrigger.checkRetainedObjects()
延迟时间为AppWatcher.config.watchDurationMillis,默认为5秒
获取ObjectWatcher.watchedObjects里retained的对象的个数,如果存在retained的对象,也就说明有观察的对象还没有被回收,没有被垃圾回收其实有两种情况,一种是垃圾回收还没有发生,一种是垃圾回收发生了但是没有回收掉;这里就主动调用gcTrigger.runGc()触发一次垃圾回收。
然后正常情况会调用dumpHeap()
代码复制了android官方的代码
InternalLeakCanary实现了OnObjectRetainedListener接口,在OnObjectRetainedListener.onObjectRetained()被调用时调用了scheduleRetainedObjectCheck(),然后又会调用heapDumpTrigger.scheduleRetainedObjectCheck() -> HeapDumpTrigger.checkRetainedObjects()
延迟时间为0,立刻调用
在App可见或不可见时,调用HeapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
在App不可见时,调用HeapDumpTrigger.scheduleRetainedObjectCheck() -> HeapDumpTrigger.checkRetainedObjects()
延迟时间为AppWatcher.config.watchDurationMillis,默认为5秒
HeapDumpTrigger.checkRetainedObjects()中会去调用checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold),根据LeakCanary.config.retainedVisibleThreshold的注释可知,dump heap会阻塞UI线程,为了减少对开发者的打扰,内存泄露的对象个数在一定数量之内不触发dump heap,checkRetainedObjects()就是做这个检查的。
如果内存泄露的对象个数在阈值允许的数量之内,会调用HeapDumpTrigger.scheduleRetainedObjectCheck(),延迟两秒执行,继续调用HeapDumpTrigger.checkRetainedObjects()
HeapDumpTrigger.checkRetainedObjects()中如果经过了checkRetainedCount()的校验后,决定dump heap了,但是发现距离上次dump heap的时间小于60秒,就不进行dump,延迟到距离上次dump的60秒以后再执行checkRetainedObjects()
在HeapDumpTrigger.dumpHeap()中,调用heapDumper.dumpHeap()返回NoHeapDump时,也就是dump heap失败时,会再调用scheduleRetainedObjectCheck()尝试再次dump heap,延迟时间5秒
按当前时间命名创建一个hprof文件
调用Debug.dumpHprofData()输出信息到创建的文件
可见其对Activity是否泄漏的判断依赖VM会将可回收的对象加入WeakReference关联的ReferenceQueue这一特性,在Demo的测试过程中我们发现这中做法在个别系统上可能存在误报,原因大致如下:
对此我们做了以下改进: