Android开发-Handler引起的内存泄漏-实验、分析、总结。
介绍
最近在恶补Handler的知识,其中就涉及到了Handler引起的内存泄露问题,网络上有很多的分析文章。我就按照这些文章的思路,写代码验证,主要是验证和记录。
使用的内存检测工具是:LeakCanary 中文使用说明
英文原文:
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
翻译得比较好的中文版:
技术小黑屋:http://droidyue.com/blog/2014/12/28/in-android-handler-classes-should-be-static-or-leaks-might-occur/
简书博客:http://www.jianshu.com/p/cb9b4b71a820
问题代码
首先根据原文的思想写出会引起内存泄露的代码。这里就不使用postDelayed()方法,发送Runnable匿名类(非静态匿名类)为了简化问题。使用的是sendEmptyMessageDelayed()
发送延时消息。
非静态匿名类:同样持有对其外部类的引用,也会导致泄漏。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">LeakActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">BaseActivity</span> {</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略其他代码</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> Handler mLeakHandler=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Handler(){<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">handleMessage</span>(Message msg) {<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.handleMessage(msg);Logger.d(msg.toString());}};<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResume</span>() {<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onResume();mLeakHandler.sendEmptyMessageDelayed(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0x1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000</span>);finish();}<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略其他代码</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
代码逻辑大概就这么多,在其他地方跳转到LeakActivity
过来就可以。
然后喜闻乐见的内存就发生了,请看下图。
内存泄露
看图分析:
- 根据图片可以分析最终的泄露发生在LeakActivity实例中
- 其他类是Handler四件套,Looper+MessageQueue+Message+Handler,它们之间互相配合实现Android内部的多线程通信,当然上面的代码只在UI线程运行。
- 在发送的延迟空消息(EmptyMessageDelayed)内部持有对handler的引用,而handler又持有对其外部类(即LeakActivity实例)的潜在引用。
- 这个消息层层传递被static修饰的静态MainLooper持有,静态变量的生命周期与应用程序一致。
- 这条引用关系会一直保持直到消息得到处理,从而,这阻止了LeakActivity被垃圾回收器回收GC,同时造成应用程序的内存泄漏。
类的生命周期
再看张图:
这是LeakActivity实例和内部的Handler实例的打印结果。
- 因为把finish方法写在onResume()方法中,生命周期快速的走了一遍。
- 24:07的时候调用了onDestroy方法,而在24:20延迟10几秒之后,Handler实例才调用handleMessage处理了消息。
- 最后在下一次的垃圾回收周期LeakActivity实例最终还是被回收了,JVM保证在一个对象所占用的内存被回收之前,如果它实现了finalize方法,则该方法一定会被调用。我这里是重写finalize方法打印出回调结果。
- 如果你在消息处理之后,使用Android Studio的Initate GC手动GC的话。Log消息结果也是一样的,还可以看到内存变化。
不会内存泄露的Handler代码
使用WeakReference弱引用持有Activity实例,静态内部类MyHandler处理消息。
相关技术点
静态内部类:不会持有对外部类的引用
弱引用:弱引用的对象拥有短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
代码如下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MyHandler</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Handler</span> {</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> WeakReference<Activity> reference;<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">MyHandler</span>(Activity activity) {reference = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> WeakReference<Activity>(activity);}<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">handleMessage</span>(Message msg) {<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.handleMessage(msg);LeakActivity activity = (LeakActivity) reference.get();<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (activity != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) {Logger.d(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"activity != null"</span>+activity.toString());} <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> {Logger.d(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"activity = null"</span>);}}}<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Handler mHandler = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> MyHandler(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>
然后mHandler
发送延迟10000毫秒的延迟空消息
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> mHandler<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sendEmptyMessageDelayed</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10000</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
分析
首先自然是没有内存泄露了,看日志打印结果
- LeakActivity实例在调用onDestroy方法。
- 系统在之后5秒左右回收了实例内存
- 当再去处理消息的时候发现弱引用持有的LeakActivity实例为空,打印结果
等等感觉还有缺什么
修改延迟时间
哪如果修改延迟消息的发送时间会发生什么。
修改代码如下:2秒的延迟,这也是平常开发比较普遍的延迟时间。
<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> mHandler<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.sendEmptyMessageDelayed</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2000</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
再看日志打印:
- 消息处理时LeakActivity实例竟然不为空。
- 进入了处理LeakActivity实例的代码块打印出了消息。
- 5秒之后才回收了实例内存。刚好就印证了上面的话:
由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象
当我们在Activity实例已经调用onDestroy方法不可见的情况下,还操作了实例修改视图做操作肯定是没有意义的,但是这样的操作也不会报出异常,只是感觉不太好。
最后的代码
通过上文的分析,WeakReference弱引用可以做到不会内存泄漏。但是实际上Handler可以直接调用方法清除掉所有的回调消息。
所以最后其实在使用Handler的时候,在生命周期的中加上一行代码,就可以了。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onDestroy</span>() {<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onDestroy();mHandler.removeCallbacksAndMessages(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
再看日志打印结果:
完美的结果!
有关内存泄露的总结
- 不要让生命周期长于Activity的对象持有到Activity的引用
- 尽量使用Application的Context而不是Activity的Context
- 尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用
- 如果使用静态内部类,将外部实例引用作为弱引用持有。
- 顶
- 3
- 踩
Android开发-Handler引起的内存泄漏-实验、分析、总结。相关推荐
- Android内存泄漏的分析和避免
内存泄漏 Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆而导致程序 ...
- android内存泄漏原因分析,Android Studio3.6的内存泄漏检测功能 VS LeakCanary
2020年2月,谷歌发布了Android Studio 3.6版.它包括一个新的"内存泄漏检测"功能.这是否意味着我们不再需要流行的内存泄漏检测库"Leak Canary ...
- [贝聊科技]使用Android Studio和MAT进行内存泄漏分析
1.Java内存分配策略 Java 程序运行时的内存分配策略有三种:静态分配.栈式分配和堆式分配.对应的存储区域如下: 静态存储区(方法区):主要存放静态数据.全局 static 数据和常量.这块内存 ...
- Android开发中常见的内存泄露案例以及解决方法总结
Android开发中常见的内存泄露案例以及解决方法总结 参考文章: (1)Android开发中常见的内存泄露案例以及解决方法总结 (2)https://www.cnblogs.com/shen-hua ...
- RK3588 Android12 DMABUF内存泄漏问题分析
RK3588 Android12 DMABUF内存泄漏问题分析 什么是DMABUF DMABUF是多媒体设备之间共享内存的一种特定buffer结构,不同设备可以通过DMABUF的fd进行跨进程共享内存 ...
- android内存泄漏原因分析,Android 内存泄漏案例分析总结(Handler)
在Android开发开发中,操作不当很容易引起内存泄漏,这里主要记录下平时遇到问题,包括:静态变量(也包含集合).非静态的内部类.Handler.监听器,尤其是 Handler 在开发中要格外的注意. ...
- Android 性能优化 - 彻底解决内存泄漏
起源 有趣的灵魂千奇百怪,内存泄漏的也是各式各样 我在15年写过一遍 文章 < android中常见的内存泄漏和解决办法>http://blog.csdn.net/wanghao20090 ...
- 火速收藏!Android 开发者必会的内存泄漏指南
[CSDN 编者按]对于众多 Android 程序员而言,在需求与应用性能之间,主要精力都会放到新需求的开发.随着项目复杂度的增加,应用性能越来越低,出现各种问题.程序员们奔波于各种"救火现 ...
- iPhone开发Swift基础07 内存泄漏检测
Instruments Instruments工具是用于动态跟踪和分析代码的工具,可以跟踪一个或者多个进程,并检测收集实时数据,使开发者更好地理解应用程序和操作系统的行为和性能. 追查代码中难以重现的 ...
最新文章
- 自定义配置app.config
- Spring MVC 解读——@Autowired
- 文件管理服务器主机,通过BlueHost主机文件管理器上传文件
- 计算机教学与课程论专业,东北师范大学专业介绍:计算机课程与教学论
- Hive Sql 时间格式化处理
- 计算机视觉与深度学习 | 开源SLAM、视觉里程计综述(SLAM、Visual Odometry)
- java扑克牌抽牌_[java,2018-06-26] 扑克牌抽牌求和问题
- C++中 引用与取地址的区别
- datastage 重启 续
- ThinkPHP框架知识的注意点
- iOS : 静态库(.framework)合并
- [原创]将本地代码共享到github的操作步骤
- 【Java】Java 使用函数的方法输出菱形(星号)
- 2、根据@FeignClient生成代理类
- swoole深入学习 2. tcp Server和tcp Client
- Android-创建简单登陆界面
- Day03 车牌识别
- Qt 之自定义搜索框QLineEdit
- 社会管理网格化 源码_全县首家镇域网格妇联——“和大王”社会治理网格化服务管理中心妇联正式成立!...
- PPT多张图片的融合插件