精华内容
下载资源
问答
  • labview性能优化内存管理,了解labview软件运行的原理,及如何优化labview代码
  • 本文从内存管理硬件架构、地址空间划分和内存管理软件架构三个方面入手,尝试对内存管理的软硬件架构做一些宏观上的分析总结。 内存管理硬件架构 因为内存管理是内核最为核心的一个功能,针对内存管理性能优化,...
  • 内存管理 内存整理 内存清理 内存优化 进程管理 启动项管理等。 支持多种语言,优化速度块等。
  • 本文转载自 ...许多公司都想把“内存优化器”(比如某卫士的点一点释放内存功能)作为他们的PC优化软件的一部卖点推销你。但是,这些软件往往非徒无益——它们不但不会加速你的电脑,反而会使你的电脑速度
    本文转载自  极客范,由 极客范 - 八卦爱好者 翻译自 Chris Hoffman原文链接: Chris Hoffman 译文链接: http://www.geekfan.net/7474/
    

    image1
    许多公司都想把“内存优化器”(比如某卫士的点一点释放内存功能)作为他们的PC优化软件的一部卖点推销你。但是,这些软件往往非徒无益——它们不但不会加速你的电脑,反而会使你的电脑速度降低。

    这些程序往往利用了初级用户的无知,向他们做出提升性能的虚假承诺。事实上,你的电脑完全知道怎么去管理它的内存(RAM)。它会使用内存来提升机器的性能——没有理由让内存白白闲着着!

    你的电脑的内存跑满了?那就对了!

    内存优化软件往往利用了群众的无知。你或许会查看一下你的电脑的内存,然后发现它跑满了——例如,你又4GB的内存,然后发现有3GB都在使用中,只有1GB的剩余空间。这一定会让某些人感到惊诧——擦!你看现在的Windows多么臃肿啊!这么可怜的可用内存,还怎么指望运行其他的程序呢?

    事实上,现代操作系统很擅长与管理内存。那3GB的使用中的内存并不一定意味着浪费。相反,你的电脑用内存来缓存数据从而加速访问。无论是你在浏览器中打开的网页、你之前运行的程序或者是任何你可能再次访问的数据,你的电脑都会把它保留在你的内存里。当你再次需要这些数据的时候,你的电脑便不需要访问你的硬盘了,仅需从内存里加载文件就可以了。

    问题的关键在于没有任何理由让内存处于空闲的状态。即使是你的内存全部用完了你需要更多的内存来运行一个程序,你的电脑也能够立即丢弃这些缓存数据,从而为运行该程序腾出空间。没有任何理由让内存处于闲置中——如果它是空的,那么就是在暴殄天物。如果它跑满了,那么它很可能会帮助你加速程序启动时间以及其他任何需要访问硬盘的东西。

    我们可以看到,下面的截图中显示只有极少量的内存真正“空闲”。相当部分的内存用做了缓存,但是对于任何程序来说这些内存仍然是可用内存。

    image2-CN

    过去,内存耗尽一般表示某处出了问题。如果你在一台电脑上运行Windows Vista操作系统,并且只有不到半GB(512MB)的内存的话,你会感觉到你的电脑时常的卡顿——它不得不时不时地访问一下硬盘,使用硬盘上的页面文件作为内存蹩脚的替代品。不过,对于大多数用户来说,现代的计算机通常都会有足够的内存。甚至一些低端的电脑发售的时候都会配有4GB的内存。除非你经常玩游戏,运行多个虚拟机或者编辑视频,不然这一配置通常来说就足足够用了。

    即使内存的问题已经困扰到了你,也没有任何理由去用内存优化软件。内存优化软件就像万灵油一样百害而无一利。

    内存优化软件如何工作

    当你使用内存优化软件的时候,你将会看到你的内存用量下降。这看上去真的是很有效的事情——毕竟你轻点按钮就把内存用量降下来了。但是,事情并不是这么简单。

    内存优化软件事实上以下面的两种方式之一工作:

    •  调用Windows API EmptyWorkingSet 来强制正在运行的程序将工作内存写入Windows的页面文件。
    • 申请大量的内存来强制Windows丢弃缓存数据,并且将程序数据写入页面文件。然后再释放申请的内存,从而降低内存用量。

    这两种伎俩确实都能够释放内存,使内存空闲。然而所有的努力不过实在让事情变得更糟罢了——现在你要运行的程序便不得不从页面文件中读取所需数据,从而话费更长的时间。任何用于缓存的内存都可以被丢弃,于是Windows便不得不从硬盘中取得它所需的数据。

    换句话来说,这些程序释放了快速存储,却把数据转移到了慢速存储,而后这些数据不得不再次移动到快速存储中。这简直太无厘头了!他们干的事儿不过是卖给了你一个需要用光照才能亮的手电筒!

    t015f7b1d041234e5a1

    如果Windows需要内存的话,它会把数据载入页面文件或者丢弃一些缓存数据。所有的这些都是在需要的时候自动完成的 ——没有理由在不必要的时候做这些事情,还让你的机器变慢。

    诸如PC清理软件,内存优化软件等等,都是骗局而已。它们只不过让不懂内存管理的人们以为它们干了些有益的事情,但实际上做的都是些有害的事情。

    如何真正“优化”你的内存

    如果你想得到更多的可用内存的话,把内存优化软件扔到垃圾箱里吧,相反你应该试试不去运行你不需要的应用——将其从系统托盘中退出,禁止无用的启动程序等等。

    如果你的工作需要更多的内存,同学你该买内存啦!内存其实相当便宜(译者按:JS作祟现在国内的内存价格不便宜!),而且安装也异常简单——从网上随便找一个教程就可以了。你需要注意的只是保证你买的内存的类型适合你的电脑。

    image4


    不错,内存优化软件能够释放你的PC的内存。但是,那实在是一件扯淡的事情——你的计算机需要使用内存来加速运行。没有理由让内存闲着下蛋!

    展开全文
  • 内存优化专家 v7.5.zip

    2019-07-14 06:19:41
    专业的内存优化软件,完全提升系统效率. >特色功能: >●采用和系统内核连接的优化核心,优化释放内存快捷简单. >●与传统排除到虚拟内存文件的内存优化完全区分. >●系统底层操作内存优化,优化后不影响程序...
  • Android内存管理优化建议

    千次阅读 2016-10-17 12:42:35
    前面我们提到过使用getMemoryClass()的方法可以...简要的获取某个应用的内存占用情况可以参考下面的示例( 关于更多内存查看的知识,可以参考这篇官方教程:Investigating Your RAM Usage )1)查看内存使用情况 通过

    OOM(OutOfMemory)
    前面我们提到过使用getMemoryClass()的方法可以得到Dalvik Heap的阈值。简要的获取某个应用的内存占用情况可以参考下面的示例( 关于更多内存查看的知识,可以参考这篇官方教程:Investigating Your RAM Usage )

    1)查看内存使用情况
    通过命令行查看内存详细占用情况:

    通过Android Studio的Memory Monitor查看内存中Dalvik Heap的实时变化

    2)发生OOM的条件
    关于Native Heap,Dalvik Heap,Pss等内存管理机制比较复杂,这里不展开描述。简单的说,通过不同的内存分配方式(malloc/mmap/JNIEnv/etc)对不同的对象(bitmap,etc)进行操作会因为Android系统版本的差异而产生不同的行为,对Native Heap与Dalvik Heap以及OOM的判断条件都会有所影响。在2.x的系统上,我们常常可以看到Heap Size的total值明显超过了通过getMemoryClass()获取到的阈值而不会发生OOM的情况,那么针对2.x与4.x的Android系统,到底是如何判断会发生OOM呢?

    Android 2.x系统 GC LOG中的dalvik allocated + external allocated + 新分配的大小 >= getMemoryClass()值的时候就会发生OOM。 例如,假设有这么一段Dalvik输出的GC LOG:GC_FOR_MALLOC free 2K, 13% free 32586K/37455K, external 8989K/10356K, paused 20ms,那么32586+8989+(新分配23975)=65550>64M时,就会发生OOM。

    Android 4.x系统 Android 4.x的系统废除了external的计数器,类似bitmap的分配改到dalvik的java heap中申请,只要allocated + 新分配的内存 >= getMemoryClass()的时候就会发生OOM,如下图所示(虽然图示演示的是art运行环境,但是统计规则还是和dalvik保持一致)

    (三)如何避免OOM总结
    前面介绍了一些基础的内存管理机制以及OOM的基础知识,那么在实践操作当中,有哪些指导性的规则可以参考呢?归纳下来,可以从四个方面着手,首先是减小对象的内存占用,其次是内存对象的重复利用,然后是避免对象的内存泄露,最后是内存使用策略优化。

    减小对象的内存占用
    避免OOM的第一步就是要尽量减少新分配出来的对象占用内存的大小,尽量使用更加轻量的对象。

    1)使用更加轻量的数据结构
    例如,我们可以考虑使用ArrayMap/SparseArray而不是HashMap等传统数据结构,下图演示了HashMap的简要工作原理,相比起Android系统专门为移动操作系统编写的ArrayMap容器,在大多数情况下,都显示效率低下,更占内存。通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效在于他们避免了对key与value的autobox自动装箱,并且避免了装箱后的解箱。

    关于更多ArrayMap/SparseArray的讨论,请参考http://hukai.me/android-performance-patterns-season-3/的前三个段落

    2)避免在Android里面使用Enum
    Android官方培训课程提到过“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具体原理请参考http://hukai.me/android-performance-patterns-season-3/,所以请避免在Android里面使用到枚举。

    3)减小Bitmap对象的内存占用
    Bitmap是一个极容易消耗内存的大胖子,减小创建出来的Bitmap的内存占用是很重要的,通常来说有下面2个措施:

    inSampleSize:缩放比例,在把图片载入内存之前,我们需要先计算出一个合适的缩放比例,避免不必要的大图载入。
    decode format:解码格式,选择ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差异。
    4)使用更小的图片
    在设计给到资源图片的时候,我们需要特别留意这张图片是否存在可以压缩的空间,是否可以使用一张更小的图片。尽量使用更小的图片不仅仅可以减少内存的使用,还可以避免出现大量的InflationException。假设有一张很大的图片被XML文件直接引用,很有可能在初始化视图的时候就会因为内存不足而发生InflationException,这个问题的根本原因其实是发生了OOM。

    内存对象的重复利用
    大多数对象的复用,最终实施的方案都是利用对象池技术,要么是在编写代码的时候显式的在程序里面去创建对象池,然后处理好复用的实现逻辑,要么就是利用系统框架既有的某些复用特性达到减少对象的重复创建,从而减少内存的分配与回收。

    在Android上面最常用的一个缓存算法是LRU(Least Recently Use),简要操作原理如下图所示:

    1)复用系统自带的资源
    Android系统本身内置了很多的资源,例如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用。这样做不仅仅可以减少应用程序的自身负重,减小APK的大小,另外还可以一定程度上减少内存的开销,复用性更好。但是也有必要留意Android系统的版本差异性,对那些不同系统版本上表现存在很大差异,不符合需求的情况,还是需要应用程序自身内置进去。

    2)注意在ListView/GridView等出现大量重复子组件的视图里面对ConvertView的复用

    3)Bitmap对象的复用
    在ListView与GridView等显示大量图片的控件里面需要使用LRU的机制来缓存处理好的Bitmap。

    利用inBitmap的高级特性提高Android系统在Bitmap分配与释放执行效率上的提升(3.0以及4.4以后存在一些使用限制上的差异)。使用inBitmap属性可以告知Bitmap解码器去尝试使用已经存在的内存区域,新解码的bitmap会尝试去使用之前那张bitmap在heap中所占据的pixel data内存区域,而不是去问内存重新申请一块区域来存放bitmap。利用这种特性,即使是上千张的图片,也只会仅仅只需要占用屏幕所能够显示的图片数量的内存大小。

    使用inBitmap需要注意几个限制条件:

    在SDK 11 -> 18之间,重用的bitmap大小必须是一致的,例如给inBitmap赋值的图片大小为100-100,那么新申请的bitmap必须也为100-100才能够被重用。从SDK 19开始,新申请的bitmap大小必须小于或者等于已经赋值过的bitmap大小。
    新申请的bitmap与旧的bitmap必须有相同的解码格式,例如大家都是8888的,如果前面的bitmap是8888,那么就不能支持4444与565格式的bitmap了。 我们可以创建一个包含多种典型可重用bitmap的对象池,这样后续的bitmap创建都能够找到合适的“模板”去进行重用。如下图所示:

    另外提一点:在2.x的系统上,尽管bitmap是分配在native层,但是还是无法避免被计算到OOM的引用计数器里面。这里提示一下,不少应用会通过反射BitmapFactory.Options里面的inNativeAlloc来达到扩大使用内存的目的,但是如果大家都这么做,对系统整体会造成一定的负面影响,建议谨慎采纳。

    4)避免在onDraw方法里面执行对象的创建
    类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动。

    5)StringBuilder
    在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”。

    避免对象的内存泄露
    内存对象的泄漏,会导致一些不再使用的对象无法及时释放,这样一方面占用了宝贵的内存空间,很容易导致后续需要分配内存的时候,空闲空间不足而出现OOM。显然,这还使得每级Generation的内存区域可用空间变小,gc就会更容易被触发,容易出现内存抖动,从而引起性能问题。

    最新的LeakCanary开源控件,可以很好的帮助我们发现内存泄露的情况,更多关于LeakCanary的介绍,请看这里https://github.com/square/leakcanary(中文使用说明http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/)。另外也可以使用传统的MAT工具查找内存泄露,请参考这里http://android-developers.blogspot.pt/2011/03/memory-analysis-for-android.html(便捷的中文资料http://androidperformance.com/2015/04/11/AndroidMemory-Usage-Of-MAT/

    1)注意Activity的泄漏
    通常来说,Activity的泄漏是内存泄漏里面最严重的问题,它占用的内存多,影响面广,我们需要特别注意以下两种情况导致的Activity泄漏:

    内部类引用导致Activity的泄漏
    最典型的场景是Handler导致的Activity泄漏,如果Handler中有延迟的任务或者是等待执行的任务队列过长,都有可能因为Handler继续执行而导致Activity发生泄漏。此时的引用关系链是Looper -> MessageQueue -> Message -> Handler -> Activity。为了解决这个问题,可以在UI退出之前,执行remove Handler消息队列中的消息与runnable对象。或者是使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的。

    Activity Context被传递到其他实例中,这可能导致自身被引用而发生泄漏。
    内部类引起的泄漏不仅仅会发生在Activity上,其他任何内部类出现的地方,都需要特别留意!我们可以考虑尽量使用static类型的内部类,同时使用WeakReference的机制来避免因为互相引用而出现的泄露。

    2)考虑使用Application Context而不是Activity Context
    对于大部分非必须使用Activity Context的情况(Dialog的Context就必须是Activity Context),我们都可以考虑使用Application Context而不是Activity的Context,这样可以避免不经意的Activity泄露。

    3)注意临时Bitmap对象的及时回收
    虽然在大多数情况下,我们会对Bitmap增加缓存机制,但是在某些时候,部分Bitmap是需要及时回收的。例如临时创建的某个相对比较大的bitmap对象,在经过变换得到新的bitmap对象之后,应该尽快回收原始的bitmap,这样能够更快释放原始bitmap所占用的空间。

    需要特别留意的是Bitmap类里面提供的createBitmap()方法:

    这个函数返回的bitmap有可能和source bitmap是同一个,在回收的时候,需要特别检查source bitmap与return bitmap的引用是否相同,只有在不等的情况下,才能够执行source bitmap的recycle方法。

    4)注意监听器的注销
    在Android程序里面存在很多需要register与unregister的监听器,我们需要确保在合适的时候及时unregister那些监听器。自己手动add的listener,需要记得及时remove这个listener。

    5)注意缓存容器中的对象泄漏
    有时候,我们为了提高对象的复用性把某些对象放到缓存容器中,可是如果这些对象没有及时从容器中清除,也是有可能导致内存泄漏的。例如,针对2.3的系统,如果把drawable添加到缓存容器,因为drawable与View的强应用,很容易导致activity发生泄漏。而从4.0开始,就不存在这个问题。解决这个问题,需要对2.3系统上的缓存drawable做特殊封装,处理引用解绑的问题,避免泄漏的情况。

    6)注意WebView的泄漏
    Android中的WebView存在很大的兼容性问题,不仅仅是Android系统版本的不同对WebView产生很大的差异,另外不同的厂商出货的ROM里面WebView也存在着很大的差异。更严重的是标准的WebView存在内存泄露的问题,看这里WebView causes memory leak - leaks the parent Activity。所以通常根治这个问题的办法是为WebView开启另外一个进程,通过AIDL与主进程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。

    7)注意Cursor对象是否及时关闭
    在程序中我们经常会进行查询数据库的操作,但时常会存在不小心使用Cursor之后没有及时关闭的情况。这些Cursor的泄露,反复多次出现的话会对内存管理产生很大的负面影响,我们需要谨记对Cursor对象的及时关闭。

    内存使用策略优化
    1)谨慎使用large heap
    正如前面提到的,Android设备根据硬件与软件的设置差异而存在不同大小的内存空间,他们为应用程序设置了不同大小的Heap限制阈值。你可以通过调用getMemoryClass()来获取应用的可用Heap大小。在一些特殊的情景下,你可以通过在manifest的application标签下添加largeHeap=true的属性来为应用声明一个更大的heap空间。然后,你可以通过getLargeMemoryClass()来获取到这个更大的heap size阈值。然而,声明得到更大Heap阈值的本意是为了一小部分会消耗大量RAM的应用(例如一个大图片的编辑应用)。不要轻易的因为你需要使用更多的内存而去请求一个大的Heap Size。只有当你清楚的知道哪里会使用大量的内存并且知道为什么这些内存必须被保留时才去使用large heap。因此请谨慎使用large heap属性。使用额外的内存空间会影响系统整体的用户体验,并且会使得每次gc的运行时间更长。在任务切换时,系统的性能会大打折扣。另外, large heap并不一定能够获取到更大的heap。在某些有严格限制的机器上,large heap的大小和通常的heap size是一样的。因此即使你申请了large heap,你还是应该通过执行getMemoryClass()来检查实际获取到的heap大小。

    2)综合考虑设备内存阈值与其他因素设计合适的缓存大小
    例如,在设计ListView或者GridView的Bitmap LRU缓存的时候,需要考虑的点有:

    应用程序剩下了多少可用的内存空间?
    有多少图片会被一次呈现到屏幕上?有多少图片需要事先缓存好以便快速滑动时能够立即显示到屏幕?
    设备的屏幕大小与密度是多少? 一个xhdpi的设备会比hdpi需要一个更大的Cache来hold住同样数量的图片。
    不同的页面针对Bitmap的设计的尺寸与配置是什么,大概会花费多少内存?
    页面图片被访问的频率?是否存在其中的一部分比其他的图片具有更高的访问频繁?如果是,也许你想要保存那些最常访问的到内存中,或者为不同组别的位图(按访问频率分组)设置多个LruCache容器。
    3)onLowMemory()与onTrimMemory()
    Android用户可以随意在不同的应用之间进行快速切换。为了让background的应用能够迅速的切换到forground,每一个background的应用都会占用一定的内存。Android系统会根据当前的系统的内存使用情况,决定回收部分background的应用内存。如果background的应用从暂停状态直接被恢复到forground,能够获得较快的恢复体验,如果background应用是从Kill的状态进行恢复,相比之下就显得稍微有点慢。

    onLowMemory():Android系统提供了一些回调来通知当前应用的内存使用情况,通常来说,当所有的background应用都被kill掉的时候,forground应用会收到onLowMemory()的回调。在这种情况下,需要尽快释放当前应用的非必须的内存资源,从而确保系统能够继续稳定运行。
    onTrimMemory(int):Android系统从4.0开始还提供了onTrimMemory()的回调,当系统内存达到某些条件的时候,所有正在运行的应用都会收到这个回调,同时在这个回调里面会传递以下的参数,代表不同的内存使用情况,收到onTrimMemory()回调的时候,需要根据传递的参数类型进行判断,合理的选择释放自身的一些内存占用,一方面可以提高系统的整体运行流畅度,另外也可以避免自己被系统判断为优先需要杀掉的应用。下图介绍了各种不同的回调参数:

    TRIM_MEMORY_UI_HIDDEN:你的应用程序的所有UI界面被隐藏了,即用户点击了Home键或者Back键退出应用,导致应用的UI界面完全不可见。这个时候应该释放一些不可见的时候非必须的资源

    当程序正在前台运行的时候,可能会接收到从onTrimMemory()中返回的下面的值之一:

    TRIM_MEMORY_RUNNING_MODERATE:你的应用正在运行并且不会被列为可杀死的。但是设备此时正运行于低内存状态下,系统开始触发杀死LRU Cache中的Process的机制。
    TRIM_MEMORY_RUNNING_LOW:你的应用正在运行且没有被列为可杀死的。但是设备正运行于更低内存的状态下,你应该释放不用的资源用来提升系统性能。
    TRIM_MEMORY_RUNNING_CRITICAL:你的应用仍在运行,但是系统已经把LRU Cache中的大多数进程都已经杀死,因此你应该立即释放所有非必须的资源。如果系统不能回收到足够的RAM数量,系统将会清除所有的LRU缓存中的进程,并且开始杀死那些之前被认为不应该杀死的进程,例如那个包含了一个运行态Service的进程。
    当应用进程退到后台正在被Cached的时候,可能会接收到从onTrimMemory()中返回的下面的值之一:

    TRIM_MEMORY_BACKGROUND: 系统正运行于低内存状态并且你的进程正处于LRU缓存名单中最不容易杀掉的位置。尽管你的应用进程并不是处于被杀掉的高危险状态,系统可能已经开始杀掉LRU缓存中的其他进程了。你应该释放那些容易恢复的资源,以便于你的进程可以保留下来,这样当用户回退到你的应用的时候才能够迅速恢复。
    TRIM_MEMORY_MODERATE: 系统正运行于低内存状态并且你的进程已经已经接近LRU名单的中部位置。如果系统开始变得更加内存紧张,你的进程是有可能被杀死的。
    TRIM_MEMORY_COMPLETE: 系统正运行于低内存的状态并且你的进程正处于LRU名单中最容易被杀掉的位置。你应该释放任何不影响你的应用恢复状态的资源。

    因为onTrimMemory()的回调是在API 14才被加进来的,对于老的版本,你可以使用onLowMemory)回调来进行兼容。onLowMemory相当与TRIM_MEMORY_COMPLETE。
    请注意:当系统开始清除LRU缓存中的进程时,虽然它首先按照LRU的顺序来执行操作,但是它同样会考虑进程的内存使用量以及其他因素。占用越少的进程越容易被留下来。
    4)资源文件需要选择合适的文件夹进行存放
    我们知道hdpi/xhdpi/xxhdpi等等不同dpi的文件夹下的图片在不同的设备上会经过scale的处理。例如我们只在hdpi的目录下放置了一张100100的图片,那么根据换算关系,xxhdpi的手机去引用那张图片就会被拉伸到200200。需要注意到在这种情况下,内存占用是会显著提高的。对于不希望被拉伸的图片,需要放到assets或者nodpi的目录下。

    5)Try catch某些大内存分配的操作
    在某些情况下,我们需要事先评估那些可能发生OOM的代码,对于这些可能发生OOM的代码,加入catch机制,可以考虑在catch里面尝试一次降级的内存分配操作。例如decode bitmap的时候,catch到OOM,可以尝试把采样比例再增加一倍之后,再次尝试decode。

    6)谨慎使用static对象
    因为static的生命周期过长,和应用的进程保持一致,使用不当很可能导致对象泄漏,在Android中应该谨慎使用static对象。

    7)特别留意单例对象中不合理的持有
    虽然单例模式简单实用,提供了很多便利性,但是因为单例的生命周期和应用保持一致,使用不合理很容易出现持有对象的泄漏。

    8)珍惜Services资源
    如果你的应用需要在后台使用service,除非它被触发并执行一个任务,否则其他时候Service都应该是停止状态。另外需要注意当这个service完成任务之后因为停止service失败而引起的内存泄漏。 当你启动一个Service,系统会倾向为了保留这个Service而一直保留Service所在的进程。这使得进程的运行代价很高,因为系统没有办法把Service所占用的RAM空间腾出来让给其他组件,另外Service还不能被Paged out。这减少了系统能够存放到LRU缓存当中的进程数量,它会影响应用之间的切换效率,甚至会导致系统内存使用不稳定,从而无法继续保持住所有目前正在运行的service。 建议使用IntentService,它会在处理完交代给它的任务之后尽快结束自己。更多信息,请阅读Running in a Background Service。

    9)优化布局层次,减少内存消耗
    越扁平化的视图布局,占用的内存就越少,效率越高。我们需要尽量保证布局足够扁平化,当使用系统提供的View无法实现足够扁平的时候考虑使用自定义View来达到目的。

    10)谨慎使用“抽象”编程
    很多时候,开发者会使用抽象类作为”好的编程实践”,因为抽象能够提升代码的灵活性与可维护性。然而,抽象会导致一个显著的额外内存开销:他们需要同等量的代码用于可执行,那些代码会被mapping到内存中,因此如果你的抽象没有显著的提升效率,应该尽量避免他们。

    11)使用nano protobufs序列化数据
    Protocol buffers是由Google为序列化结构数据而设计的,一种语言无关,平台无关,具有良好的扩展性。类似XML,却比XML更加轻量,快速,简单。如果你需要为你的数据实现序列化与协议化,建议使用nano protobufs。关于更多细节,请参考protobuf readme的”Nano version”章节。

    12)谨慎使用依赖注入框架
    使用类似Guice或者RoboGuice等框架注入代码,在某种程度上可以简化你的代码。下面是使用RoboGuice前后的对比图:

    使用RoboGuice之后,代码是简化了不少。然而,那些注入框架会通过扫描你的代码执行许多初始化的操作,这会导致你的代码需要大量的内存空间来mapping代码,而且mapped pages会长时间的被保留在内存中。除非真的很有必要,建议谨慎使用这种技术。

    13)谨慎使用多进程
    使用多进程可以把应用中的部分组件运行在单独的进程当中,这样可以扩大应用的内存占用范围,但是这个技术必须谨慎使用,绝大多数应用都不应该贸然使用多进程,一方面是因为使用多进程会使得代码逻辑更加复杂,另外如果使用不当,它可能反而会导致显著增加内存。当你的应用需要运行一个常驻后台的任务,而且这个任务并不轻量,可以考虑使用这个技术。

    一个典型的例子是创建一个可以长时间后台播放的Music Player。如果整个应用都运行在一个进程中,当后台播放的时候,前台的那些UI资源也没有办法得到释放。类似这样的应用可以切分成2个进程:一个用来操作UI,另外一个给后台的Service。

    14)使用ProGuard来剔除不需要的代码
    ProGuard能够通过移除不需要的代码,重命名类,域与方法等等对代码进行压缩,优化与混淆。使用ProGuard可以使得你的代码更加紧凑,这样能够减少mapping代码所需要的内存空间。

    15)谨慎使用第三方libraries
    很多开源的library代码都不是为移动网络环境而编写的,如果运用在移动设备上,并不一定适合。即使是针对Android而设计的library,也需要特别谨慎,特别是在你不知道引入的library具体做了什么事情的时候。例如,其中一个library使用的是nano protobufs, 而另外一个使用的是micro protobufs。这样一来,在你的应用里面就有2种protobuf的实现方式。这样类似的冲突还可能发生在输出日志,加载图片,缓存等等模块里面。另外不要为了1个或者2个功能而导入整个library,如果没有一个合适的库与你的需求相吻合,你应该考虑自己去实现,而不是导入一个大而全的解决方案。

    16)考虑不同的实现方式来优化内存占用
    在某些情况下,设计的某个方案能够快速实现需求,但是这个方案却可能在内存占用上表现的效率不够好。例如:

    对于上面这样一个时钟表盘的实现,最简单的就是使用很多张包含指针的表盘图片,使用帧动画实现指针的旋转。但是如果把指针扣出来,单独进行旋转绘制,显然比载入N多张图片占用的内存要少很多。当然这样做,代码复杂度上会有所增加,这里就需要在优化内存占用与实现简易度之间进行权衡了。

    写在最后:

    设计风格很大程度上会影响到程序的内存与性能,相对来说,如果大量使用类似Material Design的风格,不仅安装包可以变小,还可以减少内存的占用,渲染性能与加载性能都会有一定的提升。
    内存优化并不就是说程序占用的内存越少就越好,如果因为想要保持更低的内存占用,而频繁触发执行gc操作,在某种程度上反而会导致应用性能整体有所下降,这里需要综合考虑做一定的权衡。
    Android的内存优化涉及的知识面还有很多:内存管理的细节,垃圾回收的工作原理,如何查找内存泄漏等等都可以展开讲很多。OOM是内存优化当中比较突出的一点,尽量减少OOM的概率对内存优化有着很大的意义。
    参考资料:

    Google I/O 2011: Memory management for Android Apps
    Managing Your App’s Memory
    Avoiding memory leaks
    Android性能优化典范 - 第3季
    Android性能优化典范 - 第2季
    Android性能优化典范
    Android性能优化之内存篇
    需要讨论直接加群,扫码直接进入!
    这里写图片描述

    展开全文
  • App性能优化:内存优化

    千次阅读 2020-01-03 14:22:41
    App性能优化:内存优化 本篇主要探讨app性能优化相关的知识点,预计20年2月底前完成 内存优化工具 内存管理机制 内存都懂解决 内存泄漏解决 MAT详解 小结 ...

    App性能优化:内存优化

    目录:

    1. 内存优化工具
    2. 内存管理机制
    3. 内存抖动解决
    4. 内存泄漏解决
    5. MAT详解
    6. 小结
    背景介绍
    • 内存是大问题但缺乏关注
    • 压死骆驼的最后一根稻草
    表现形式
    • 内存抖动:锯齿状,GC导致卡顿
    • 内存泄漏:可用内存减少、频繁GC
    • 内存溢出:OOM、程序异常

    1、工具选择

    • Memory Profiler
    • Memory Analyzer
    • LeakCanary
    Memory Profiler
    1. 实时图标展示内存使用量
    2. 识别内存泄漏、抖动
    3. 提供捕获堆转储、强制GC以及跟踪内存分配的能力
    Memory Profiler的使用
    1. 非常直观
    2. 线下平时使用
    Memory Analyzer(MAT)
    1. 强大的Java heap 分析工具,帮助查找内存泄漏和内存占用
    2. 生成整体报告,分析问题
    3. 线下深入使用
    LeakCanary
    1. 自动内存泄漏检测
    2. 线下集成

    2、android内存管理机制

    Java内存管理机制

    在这里插入图片描述

    Java内存回收算法-标记清除算法
    • 标记出所有需要回收的对象
    • 统一回收所有被标记的对象
      在这里插入图片描述
    标记回收算法存在的问题
    • 标记和清除的效率不高
    • 产生大量的内存碎片
    Java内存回收算法之 复制算法
    • 将内存分成两份,只将数据存储在其中一块上。
    • 当需要垃圾回收时,也是标记出废弃的数据,然后将有用数据复制到另一块内存上,最后将第一块内存全部清除
      在这里插入图片描述
    复制算法的问题
    • 实现简单,运行高效
    • 浪费一半空间,代价大
    Java内存回收算法之 标记整理算法
    1. 标记过程与“标记-清除算法”一样
    2. 存活对象往一端移动
    3. 清理其余内存
      在这里插入图片描述
    标记整理算法的特点
    1. 避免标记-清理导致的内存碎片
    2. 避免复制算法的空间浪费
    Java内存回收算法之 分代收集算法
    1. 结合多种收集算法优势
    2. 新生带对象存活率低:复制算法
    3. 老年代对象存活率高:标记-整理算法
    Android内存管理机制
    • 内存弹性分配,分配值和最大值受具体设备影响
    • OOM场景:内存真正不足,可用内存不足
    Dalvik 与Art区别
    • Dalvik仅固定一种回收算法
    • Art回收算法可运行期选择
    • Art具备内存整理能力,减少内存空洞
    Low Memory killer
    • 进程分类:前端、可见、服务、后台、空进程,优先级依次降低
    • 回收收益

    内存抖动案例

    ######制造内存抖动

        companion object {
            var datas: ArrayList<TestClass>? = null
            val handler = object : Handler() {
                override fun handleMessage(msg: Message) {
                    //创造内存抖动
                    for (i in 0..100) {
                        datas = ArrayList<TestClass>(100000)
                    }
                    sendEmptyMessageDelayed(0, 1000)
                }
            }
        }
    

    在这里插入图片描述

    内存抖动解决技巧
    1. 找循环或者频繁调用的地方
    2. 通过Profiler定位,锯齿状或者频繁的GC

    内存泄漏

    • 定义:内存中存在没有用的对象,又无法回收
    • 表现:内存抖动、可用内存逐渐减少

    内存泄漏案例

    1. 静态变量持有Activity引用导致Activity无法被回收
    //定义一个接口
    public interface Callback {
    
        void doOperation();
    }
    //定义持有Activity引用的类
    public class CallbackMananger {
        public static ArrayList<Callback> sCallbacks = new ArrayList();
    
        public static void addCallback(Callback callback) {
            sCallbacks.add(callback);
        }
    
        public static void removeCallBack(Callback callback) {
            sCallbacks.remove(callback);
        }
    }
    
    
    1. 在生成LeakCanaryActivity,显示一张图片
    
    class MemoryLeakActivity : AppCompatActivity(), Callback {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_memory_leak)
            val bitmap = BitmapFactory.decodeResource(resources, R.drawable.icon_leaktest)
            iv.setImageBitmap(bitmap)
            //保存Activity引用
            CallbackMananger.addCallback(this)
        }
    
        override fun doOperation() {
    
        }
    }
    
    
    1. 重复打开关闭 页面,即可在Profiler中看到内存成阶梯状上升,如下图所示:
      在这里插入图片描述
      显然:这里每次GC的的时候并没有导致MemoryLeakActivity被回收,内存图形呈现阶梯状显示。

    2. 使用MAT分析内存泄漏
      1. 进入官网下载MAT工具:MAT下载地址
      2. 下载对应系统版本
      在这里插入图片描述

    3. 安装MAT工具,双击zip文件解压后得到mat.app
      在这里插入图片描述

    4. 获取堆文件 Heap Dump
      在这里插入图片描述

    5. 将文件存到本地
      在这里插入图片描述
      在这里插入图片描述

    6. 注意这里是Android的hprof文件,需要使用android 的platform-tool里面的hprof-conv工具对文件进行一次格式转化,转化命令如下:
      ./hprof-conv /Users/hudingpeng/Desktop/memory-20200221T114049.hprof 2.hprof
      在这里插入图片描述

    7. 这样在platform-tools目录下会生成一个2.hprof文件,如下图所示:
      在这里插入图片描述

    8. 打开MAT工具:

      1. 直接点击mat.app会报错,按照以下步骤运行
      2. 右键mat.app => 显示包内容 =>进入 mat.app/Contents/MacOS ,此目录下就有工具MemoryAnalyzer =>双击直接打开工具就行了
        在这里插入图片描述
    9. 在这里插入图片描述
      10.点击open a Heap Dump选择我们的转化后的文件2.hprof 文件即可,下面分析MAT工具的一些常用用法

    MAT工具分析内存泄漏

    1. 打开hprot文件,选择Histogram
      在这里插入图片描述

    2. 搜索我们的泄漏的MemoryLeakActivity,可以看到有4个MemoryLeakActivity对象,表示已经泄漏了
      在这里插入图片描述

    3. 右键选择查看with incoming references
      在这里插入图片描述

    4. 选择一个,点击查看到GC Root的路径,看到具体引用的地方
      在这里插入图片描述
      在这里插入图片描述
      这样我们就看到了具体泄漏的地方就是,CallbackManager类里面的静态变量sCallbacks

    5. 点击Group by package 可以按包名排序
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      这样也可以很方便看到我们的包名下的类对象生成的情况,这里也可以看到MemoryLeakActivity在内存里有4个对象

    6. 第三个菜单项:dominator_tree 视图,显示对象占用内存的百分比
      在这里插入图片描述
      可以看到对象占用内存的百分比,给我们的内存优化提供一定的参考

    7. 第四个菜单项:OQL,相当于一种数据查询语言,我们直接搜索我们的类,点击感叹号查询,如下图所示
      在这里插入图片描述

    8. Top Consumer条目:通过图表的形式显示占用内存最多的对象
      在这里插入图片描述
      在这里插入图片描述
      这对我们的内存占用优化也是一个不错的参考

    关于BitMap的优化

    Btimap的内存模型
    1. 获取Bitmap占用的内存

      1. getByteCount()方法
      2. 宽 x 高 x 一像素占用的内存
    2. 常规方式:
      背景:图片对内存大小至关重要、图片宽高大于控件宽高

    3. 通过Epic ARTHook优雅检测不合理的图片
      Epic:Epic 是一个在虚拟机层面、以 Java Method 为粒度的 运行时 AOP Hook 框架。简单来说,Epic 就是 ART 上的 Dexposed(支持 Android 4.0 ~ 10.0)。它可以拦截本进程内部几乎任意的 Java 方法调用,可用于实现 AOP 编程、运行时插桩、性能分析、安全审计等。
      Epic 被 VirtualXposed 以及 太极 使用,用来实现非 Root 场景下的 Xposed 功能,已经经过了相当广泛的验证。
      非常厉害的AOP框架,参考连接:Epic AOP框架
      这里我们Hook setImageBitmap方法:

    import android.graphics.Bitmap;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.util.Log;
    import android.view.View;
    import android.view.ViewTreeObserver;
    import android.widget.ImageView;
    
    import com.optimize.performance.utils.LogUtils;
    import com.taobao.android.dexposed.XC_MethodHook;
    
    public class ImageHook extends XC_MethodHook {
    
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            super.afterHookedMethod(param);
            // 实现我们的逻辑
            ImageView imageView = (ImageView) param.thisObject;
            checkBitmap(imageView,((ImageView) param.thisObject).getDrawable());
        }
    
    
        private static void checkBitmap(Object thiz, Drawable drawable) {
            if (drawable instanceof BitmapDrawable && thiz instanceof View) {
                final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
                if (bitmap != null) {
                    final View view = (View) thiz;
                    int width = view.getWidth();
                    int height = view.getHeight();
                    if (width > 0 && height > 0) {
                        // 图标宽高都大于view带下的2倍以上,则警告
                        if (bitmap.getWidth() >= (width << 1)
                                && bitmap.getHeight() >= (height << 1)) {
                            warn(bitmap.getWidth(), bitmap.getHeight(), width, height, new RuntimeException("Bitmap size too large"));
                        }
                    } else {
                        final Throwable stackTrace = new RuntimeException();
                        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                            @Override
                            public boolean onPreDraw() {
                                int w = view.getWidth();
                                int h = view.getHeight();
                                if (w > 0 && h > 0) {
                                    if (bitmap.getWidth() >= (w << 1)
                                            && bitmap.getHeight() >= (h << 1)) {
                                        warn(bitmap.getWidth(), bitmap.getHeight(), w, h, stackTrace);
                                    }
                                    view.getViewTreeObserver().removeOnPreDrawListener(this);
                                }
                                return true;
                            }
                        });
                    }
                }
            }
        }
    
    
        private static void warn(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight, Throwable t) {
            String warnInfo = new StringBuilder("Bitmap size too large: ")
                    .append("\n real size: (").append(bitmapWidth).append(',').append(bitmapHeight).append(')')
                    .append("\n desired size: (").append(viewWidth).append(',').append(viewHeight).append(')')
                    .append("\n call stack trace: \n").append(Log.getStackTraceString(t)).append('\n')
                    .toString();
    
            LogUtils.i(warnInfo);
        }
    
    }
    
    

    在App onCreate方法里注册要Hook的方法,传入ImageHook

     DexposedBridge.hookAllConstructors(ImageView.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    DexposedBridge.findAndHookMethod(ImageView.class, "setImageBitmap", Bitmap.class, new ImageHook());
                }
            });
    

    more:LeakCanary 监控内存泄漏

    内存优化总结

    优化大方向
    1. 内存泄漏
    2. 内存抖动
    3. Btimap
    优化细节
    1. LargeHeap属性 (建议开启,大概率能申请到更多内存)
    2. onTrimMemory (系统块干掉app了,可以手动清理界面,跳转到主界面)
    3. 使用系统优化过的集合:SparseArray
    4. 谨慎使用SharedPreferences
    5. 谨慎使用外部库
    6. 业务架构设计合理
    展开全文
  • Android 性能优化之内存优化

    万次阅读 2016-12-18 20:33:11
    Android 性能优化之内存优化 Android 应用程序在开发的过程中内存的准确控制是判断一个程序好坏的重要标准之一: 一、假如我们开发的程序内存溢出、泄漏了会引发那些实质性的问题呢?  1、程序卡顿、响应速度变慢。...

    Android 性能优化之内存优化

    Android 应用程序在开发的过程中内存的准确控制是判断一个程序好坏的重要标准之一:

    一、假如我们开发的程序内存溢出、泄漏了会引发那些实质性的问题呢?

       1、程序卡顿、响应速度变慢。

       2、开启其他程序的时候,内存泄漏的程序放在后台没有进行关闭,但是也可能会莫名其妙的消失(内存越大它在,在后台越有可能死掉,如果内存小可能在后台停留的时间越长)

       3、甚至有的时候会直接崩溃。

    二、面对内存溢出这些可能出现的问题,走入正题,先说一下Android的内存机制

           Android的程序是由java语言进行开发的,所以Android的内存管理与Java的内存管理相似。到底什么东西需要为之分配内存的?对象,所有对象在java堆内分配空间;然而对象的释放是由垃圾回收器来完成的。C/C++中的内存机制是“谁污染,谁治理”,java对于这一点进行了比较人性化的改善,专门设计了一个专门的清洁工GC

           那么GC怎么能够确认某一个对象是不是已经被废弃了呢?Java采用了有向图的原理。Java将引用关系考虑为图的有向边,有向边从引用者指向引用对象。线程对象可以作为有向图的起始顶点,该图就是从起始顶点开始的一棵树,根顶点可以到达的对象都是有效对象,GC不会回收这些对象。如果某个对象 (连通子图)与这个根顶点不可达(注意,该图为有向图),那么我们认为这个(这些)对象不再被引用,可以被GC回收。(本段之前也不是很理解,通过查询的具体GC怎么进行回收的。)

    三、那到底什么是内存溢出(OOM)呢?它是怎么发生的呢?

            我们先从原理上说一下内存溢出和它的发生: 相信读者都读过一些Android开发的书籍,书中都会讲到Android系统框架,其中有一个Dalvik讲解,没错Android的虚拟机是基于寄存器的Dalvik的,一般情况它的最大堆的大小就是16M。Android系统会为每一个应用程序分配这个16M的Dalvik,只有16M当然我们能利用的内存空间是相当有限的了,如果我们开发的内存空间超过了16M就会出现内存溢出现象OOM(out of Memory)。

            原理上说完了,其实结合开发,概括起来内存不够用就两种情况:

          (1)内存泄漏:由于在代码编写的过程中,长期的保留了某种资源的引用,让该资源得不到释放。

          (2)保留了多个消耗大内存的对象,导致程序内存超过了16M的限制。

    针对以上着两种情况,以及结合我在开发过程中遇到的和内存优化有关系的问题,在下面我会一一进行解释说明:

    问题一:静态变量导致的内存泄漏,这是最简单的内存泄露

            static是Java中的一个关键字,它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例,尤其 Context,因为它出现的内存泄漏错误很多,在开发过程中千万不要出现

                               public static Context mContext;

                                mContext=this;

         如果将Activity赋值到了mContext,当退出这个Activity的时候,即使Activity已经Ondestory,但是仍然会有对象保存它的引用,因此这个Activity仍然得不到释放。

    对于这种情况应该如何避免呢:(1)应该尽量避免static成员变量引用资源耗费过多的实例,就像Context。

                                                             (2)应该尽量使用Application中的Context,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。

    问题二:属性动画导致的内存泄漏

        Android 3.0以后出现了属性动画,在属性动画中有一类无限循环的动画,如果我们在开发过程中播放了此类动画而且没有在onDestory中去停止动画,那么动画会一直播放下去,虽然在界面中无法看到该东湖效果了,最主要的是这个时候Activity中呢个要执行动画的view会被动画持有,而View又持有了Activity,最终导致Activity也无法得到释放。

            以下面的代码为例:

         mImageview=(Imageview)findViewById(R.id.a);

         ObjectAnimator animator=ObjectAnimator.ofFloat(mImagview,"rotation",animator.setRepeatCount(ValueAnimator.INFINITE));

        animator.start();

    对于上面的这段代码是无限循环的动画,但是会泄漏当前的Activity,解决办法就是在onDestory中调用animator.cancel();来停止动画

    问题三:静态内部类的使用防止Activity中的对象泄漏(用到弱引用)

        首先说一下我们为什么要用静态内部类呢,因为静态类不持有外部类对象,这样的话Activity就可以随便进行回收了。但是有些时候,就像假如我们想通过Handler进行通信的时候,将Handler设为静态内部类就无法操作Activity中的内容了,这个时候我们还要用到弱引用

         以Handler声明为静态内部类为例子进行讲解:

     在一个定义的线程中执行:  ihandler.sendEmptyMessage(SUCCESS);
    声明一个静态内部类:                 

    private static class IHandler extends Handler {
            private final WeakReference<Activity> mActivity;
            public IHandler(Login login) {
                mActivity = new WeakReference<Activity>(login);
            }

            @Override
            public void handleMessage(Message msg) {
                int flag = msg.what;
                switch (flag) {
                case 0:
                    String errorMsg = (String) msg.getData().getSerializable(
                            "ErrorMsg");
                    ((Login) mActivity.get()).showTip(errorMsg);
                    break;
                case SUCCESS:
                    ((Login) mActivity.get()).finish();
                    break;
                }
            }
        }

    在线程开启后会通过Handler进行通信,但是要在静态内部类IHandler中操作Activity,这时候又要避免内存泄漏我们就用到了静态内部类,静态内部不持有外部类的对象,所以用到了弱引用,注意,一个弱引用指向的Activity,在回收的时候是没有影响的,在GC检查的时候直接将Activity回收掉,内存泄漏的问题也不会出现了。

    问题四:在操作数据库的时候Cursor忘记关闭

       Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,如果查询得到的数据量较小时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。
        然而如果Cursor的数据量特表大,特别是如果里面有Blob信息时,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编程者手动的将Cursor close掉,因为在源代码中我们发现,如果等到垃圾回收器来回收时,会给用户以错误提示。
        所以我们使用Cursor的方式一般如下:
        Cursor cursor = null;  
        try {  
            cursor = mContext.getContentResolver().query(uri,null, null,null,null);  
            if(cursor != null) {  
                cursor.moveToFirst();  
                //do something  
            }  
        } catch (Exception e) {  
            e.printStackTrace();    
        } finally {  
            if (cursor != null) {  
               cursor.close();  
            }  
        } 
        有一种情况下,我们不能直接将Cursor关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭。
        @Override  
        protected void onDestroy() {        
            if (mAdapter != null && mAdapter.getCurosr() != null) {  
                mAdapter.getCursor().close();  
            }  
            super.onDestroy();   
        } 
      CursorAdapter中的changeCursor函数,会将原来的Cursor释放掉,并替换为新的Cursor,所以你不用担心原来的Cursor没有被关闭。
      你可能会想到使用Activity的managedQuery来生成Cursor,这样Cursor就会与Acitivity的生命周期一致了,多么完美的解决方法!然而事实上managedQuery也有很大的局限性。 managedQuery生成的Cursor必须确保不会被替换,因为可能很多程序事实上查询条件都是不确定的,因此我们经常会用新查询的Cursor来替换掉原先的Cursor。因此这种方法适用范围也是很小。

    问题5:IO、File等资源未释放掉

          对于这种情况相信开发者再熟悉不过也不会范这种低级的错误,文件、流等是相当耗费内存资源的,在使用完成后一定要关闭,此乃大忌。。。。

    问题6:在Android中Adapter使用十分广泛,特别是在list中。所以adapter是数据的 “集散地” ,所以对其进行内存优化是很有必要的。Adapter中ViewHoler与ContentView的使用也能节省内存消耗:一个内存溢出的重要点

    VIewHoler是利用ListView的一种视图缓存机制,避免了每次调用getView()的时候通过fingViewById()实例控件(避免了每次都要寻找控件内存消耗),使用ViewHlder能够提高50%以上的效率,而使用ConvertView能够进行view的缓存,直接将子布局转换成View进行缓存,然后每次再进来的时候可以用过tag找到缓存的布局(避免了每次布局的转化寻找消耗的内存)。

    实例代码如下:

      @Override  
        public View getView(int position, View convertView, ViewGroup parent) {  
            ViewHolder vHolder = null;  
            //如果convertView对象为空则创建新对象,不为空则复用    
            if (convertView == null) {  
                convertView = inflater.inflate(..., null);  
                // 创建 ViewHodler 对象    
                vHolder = new ViewHolder();  
                vHolder.img= (ImageView) convertView.findViewById(...);  
                vHolder.tv= (TextView) convertView.findViewById(...);  
                // 将ViewHodler保存到Tag中(Tag可以接收Object类型对象,所以任何东西都可以保存在其中)  
                convertView.setTag(vHolder);  
            } else {  
                //当convertView不为空时,通过getTag()得到View    
                vHolder = (ViewHolder) convertView.getTag();  
            }  
            // 给对象赋值,修改显示的值    
            vHolder.img.setImageBitmap(...);  
            vHolder.tv.setText(...);  
            return convertView;  
        }  
        //将显示的View 包装成类    
        static class ViewHolder {  
            TextView tv;  
            ImageView img;  
        } 

    由于明天要期末考试,我先去复习一会,还有两个重要的模块bitmap线程池的使用明天考完试完成。。。可怜可怜



    展开全文
  • Unity内存优化

    千次阅读 2018-05-25 13:43:44
    内存的开销无外乎以下三大部分:1.资源内存占用;2.引擎模块自身内存占用;3.托管堆内存占用。资源内存占用一、纹理纹理资源可以说是几乎所有游戏项目中占据最大内存开销的资源。一个6万面片的场景,网格资源最大才...
  • Unity内存优化经验分享

    千次阅读 2017-01-08 12:55:34
    笔者介绍:姜雪伟,IT公司技术... 内存优化不论是游戏开发还是软件开发,都会涉及到这个问题,这个也是所有程序员绕不过的问题,必须要解决的。特别是在移动端盛行的时代,由于硬件的限制,这个问题愈发显得突出。开
  • 在基于ue的手游开发中,经常会发现android系统的实际内存占用要比我们预估的高很多,优化内存的占用就要先明确究竟每1k实际的内存占用分布在哪里及如何运用工具有效的获取真实的内存组成,本文将结合项目经验详细...
  • 全免费专业的内存优化软件 完全提升系统效率。已破解永久免费 特色功能: ●采用和系统内核连接的优化核心,优化释放内存快捷简单. ●与传统排除到虚拟内存文件的内存优化完全区分. ●系统底层操作内存优化,优化后...
  • App内存占用优化

    千次阅读 2017-01-12 18:47:04
    RAM(Random-access memory)在任何软件开发中都是非常宝贵的资源,移动操作系统由于其物理内存的局限性更是如此。尽管ART(Android Runtime)与Dalvik虚拟机会执行常规的垃圾回收,但这并不意味着可以忽略App中的...
  • , 关于系统性能优化,《嵌入式Linux内存使用与性能优化》不同于同类书侧重于编程语法或者发挥硬件性能的做法,而是着眼于大型软件项目性能优化实践,阐明了逻辑优化与代码优化之间的辩证关系,提出了软件优化层次的...
  • Random Access Memory(RAM)在任何软件开发环境中都是一个很宝贵的资源。这一点在物理内存通常很有限的移动操作系统上,显得尤为突出。尽管Android的Dalvik虚拟机扮演了常规的垃圾...一、Android系统是如何管理内存
  • C语言图书管理系统设计报告

    万次阅读 多人点赞 2017-06-20 17:37:54
    源代码:https://blog.csdn.net/k_young1997/article/details/73480766 XXXX大学 C语言课程设计报告 ...题 目 图书管理系统设计 专业班级 XXXX级计算机科学与技术本科X班 组 别 计科第...
  • Android内存管理机制官方详解文档

    千次阅读 2020-12-09 12:40:54
    很早之前写过一篇《Android内存管理机制详解》点击量已7万+,现把Google官方文档整理输出一下,供各位参考。 一、内存管理概览 Android 运行时 (ART) 和 Dalvik 虚拟机使用分页和内存映射来管理内存。这意味着应用...
  • 深入浅出:CPU,GPU,内存优化

    万次阅读 2016-08-18 15:28:19
    前言:看看优化需要从哪里着手CPU的方面的优化:GPU的优化内存优化更新,使用Unity Profiler工具检测内存 前言: 刚开始写这篇文章的时候选了一个很土的题目。。。《Unity3D优化全解析
  • impala内存优化

    千次阅读 2017-10-12 17:52:56
     在介绍Impala内存优化技巧之前,我们先来看一下Impala官方针对内存溢出问题所作出的努力。Impala从Impala 1.4 for CDH4、CDH5.1版本开始新增了“SQL Operations that Spill to Disk”功能,即当Impala内存运算溢出...
  • Android 内存管理机制

    千次阅读 2018-09-03 14:41:45
    本文主要包括三大部分内容: 内存管理基础:从整个计算机领域... Android的内存管理相关知识:Android又不同于Linux,它是一个移动操作系统,因此其内存管理上也有自己的特性,这一部分详细讲述Android的内存管理...
  • 本篇是 Android 内存优化的进阶篇,难度可以说达到了炼狱级别,建议对内存优化不是非常熟悉的仔细看看前篇文章: Android性能优化之内存优化,其中详细分析了以下几大模块: 1)、Android的内存管理机制 2)、优化...
  • Linux性能优化之CPU、内存、IO优化

    万次阅读 多人点赞 2018-01-10 20:31:39
    这里很设计到很多的内容,包括Linux内核、CPU架构以及Linux内核对资源的分配以及管理,了解进程的创建过程等。这方面由于篇幅较多,所以我的文章就不过多介绍。接下来的几篇文章中,都是讲解如何发现应用程序故障...
  • android 内存优化

    千次阅读 2016-05-25 17:08:38
    最近在研究一个安卓项目内存优化的问题,确实这是一个比较系统的工程,和个人的代码习惯以及对jvm原理的掌握有很大关系,下面提示一些注意点 1. 内存优化  Android系统对每个软件所能使用的RAM空间...
  • Impala内存优化实战案例

    千次阅读 2016-12-23 20:01:09
    Impala内存优化实战案例 畅游DT时代(李珂) · 2016-03-26 01:23 文章来源:中国联通网研院网优网管部——IT技术研究团队 作者:李珂 一. 引言  Hadoop生态中的NoSQL数据分析...
  • ●进程管理:可识别出非系统自带的模块,区别于其他进程管理软件。 ●启动管理:加快系统启动的速度,删除无用的启动程序。 ●一键优化:根据您的系统配置情况,全自动定制优化方案,自动优化系统参数。
  • 发一个功能十分强大的小软件,全绿色,集内存管理,进程管理,系统优化等等等等的所有优化工具,完全可以替代优化大师,超级兔子等软件
  • 内存优化专家 V7.1

    2010-07-02 15:49:42
    专业的内存优化软件.完全提升系统效率.产品已经通过英特尔软件认证! 特色功能: ●采用和系统内核连接的优化核心,优化释放内存快捷简单. ●与传统排除到虚拟内存文件的内存优化完全区分. ●系统底层操作内存优化,...
  • 软件开发性能优化经验总结

    千次阅读 2019-05-21 16:19:00
    性能优化软件开发过程中必不可少,但又很困难的工作。这里是我长期对C/C++开发的性能优化的经验总结。 2 原则 性能优化必须遵循必要的原则进行。 2.1 明确目标 优化前必须有个明确的目标。目标可以有...
  • Unity性能优化内存篇(上)

    万次阅读 2016-12-14 18:45:21
    无论是游戏还是VR应用,内存管理都是其研发阶段的重中之重。 然而,在我们测评过的大量项目中,90%以上的项目都存在不同程度的内存使用问题。就目前基于Unity引擎开发的移动游戏和移动VR游戏而言,内存的开销无外乎...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 186,819
精华内容 74,727
关键字:

内存优化管理软件