介绍

最近在恶补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引起的内存泄漏-实验、分析、总结。相关推荐

  1. Android内存泄漏的分析和避免

    内存泄漏 Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(heap)挤爆而导致程序 ...

  2. android内存泄漏原因分析,Android Studio3.6的内存泄漏检测功能 VS LeakCanary

    2020年2月,谷歌发布了Android Studio 3.6版.它包括一个新的"内存泄漏检测"功能.这是否意味着我们不再需要流行的内存泄漏检测库"Leak Canary ...

  3. [贝聊科技]使用Android Studio和MAT进行内存泄漏分析

    1.Java内存分配策略 Java 程序运行时的内存分配策略有三种:静态分配.栈式分配和堆式分配.对应的存储区域如下: 静态存储区(方法区):主要存放静态数据.全局 static 数据和常量.这块内存 ...

  4. Android开发中常见的内存泄露案例以及解决方法总结

    Android开发中常见的内存泄露案例以及解决方法总结 参考文章: (1)Android开发中常见的内存泄露案例以及解决方法总结 (2)https://www.cnblogs.com/shen-hua ...

  5. RK3588 Android12 DMABUF内存泄漏问题分析

    RK3588 Android12 DMABUF内存泄漏问题分析 什么是DMABUF DMABUF是多媒体设备之间共享内存的一种特定buffer结构,不同设备可以通过DMABUF的fd进行跨进程共享内存 ...

  6. android内存泄漏原因分析,Android 内存泄漏案例分析总结(Handler)

    在Android开发开发中,操作不当很容易引起内存泄漏,这里主要记录下平时遇到问题,包括:静态变量(也包含集合).非静态的内部类.Handler.监听器,尤其是 Handler 在开发中要格外的注意. ...

  7. Android 性能优化 - 彻底解决内存泄漏

    起源 有趣的灵魂千奇百怪,内存泄漏的也是各式各样 我在15年写过一遍 文章 < android中常见的内存泄漏和解决办法>http://blog.csdn.net/wanghao20090 ...

  8. 火速收藏!Android 开发者必会的内存泄漏指南

    [CSDN 编者按]对于众多 Android 程序员而言,在需求与应用性能之间,主要精力都会放到新需求的开发.随着项目复杂度的增加,应用性能越来越低,出现各种问题.程序员们奔波于各种"救火现 ...

  9. iPhone开发Swift基础07 内存泄漏检测

    Instruments Instruments工具是用于动态跟踪和分析代码的工具,可以跟踪一个或者多个进程,并检测收集实时数据,使开发者更好地理解应用程序和操作系统的行为和性能. 追查代码中难以重现的 ...

最新文章

  1. 自定义配置app.config
  2. Spring MVC 解读——@Autowired
  3. 文件管理服务器主机,通过BlueHost主机文件管理器上传文件
  4. 计算机教学与课程论专业,东北师范大学专业介绍:计算机课程与教学论
  5. Hive Sql 时间格式化处理
  6. 计算机视觉与深度学习 | 开源SLAM、视觉里程计综述(SLAM、Visual Odometry)
  7. java扑克牌抽牌_[java,2018-06-26] 扑克牌抽牌求和问题
  8. C++中 引用与取地址的区别
  9. datastage 重启 续
  10. ThinkPHP框架知识的注意点
  11. iOS : 静态库(.framework)合并
  12. [原创]将本地代码共享到github的操作步骤
  13. 【Java】Java 使用函数的方法输出菱形(星号)
  14. 2、根据@FeignClient生成代理类
  15. swoole深入学习 2. tcp Server和tcp Client
  16. Android-创建简单登陆界面
  17. Day03 车牌识别
  18. Qt 之自定义搜索框QLineEdit
  19. 社会管理网格化 源码_全县首家镇域网格妇联——“和大王”社会治理网格化服务管理中心妇联正式成立!...
  20. PPT多张图片的融合插件

热门文章

  1. eXtremeTable -
  2. 解决微星主板点击睡眠后电脑死机
  3. c语言 获取文件修改时间,C语言中用于修改文件的存取时间的函数使用
  4. 歌曲排行榜html页面,音乐组合排行板_音乐排行榜网页模板
  5. 通信工程考研英语复试专有名词翻译
  6. 2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)
  7. 【小米路由器3】breed刷机救砖-nand flash硬改SPI flash-编程器救砖(解决ttl无法救砖问题)
  8. 项目管理心得:一个项目经理的个人体会、经验总结
  9. Extreme DAX中文第1章 商业智能中的DAX
  10. Java正则匹配淘口令