当前位置: 首页 > news >正文

定制小程序网站开发公司品牌推广外包公司

定制小程序网站开发公司,品牌推广外包公司,seo怎么收费seo,网站后台内容不更新一、内存优化概念 1.1 为什么要做内存优化#xff1f; 内存优化一直是一个很重要但却缺乏关注的点#xff0c;内存作为程序运行最重要的资源之一#xff0c;需要运行过程中做到合理的资源分配与回收#xff0c;不合理的内存占用轻则使得用户应用程序运行卡顿、ANR、黑屏 内存优化一直是一个很重要但却缺乏关注的点内存作为程序运行最重要的资源之一需要运行过程中做到合理的资源分配与回收不合理的内存占用轻则使得用户应用程序运行卡顿、ANR、黑屏重则导致用户应用程序发生 OOMout of memory崩溃。在你认真跟踪下来可能会发现内存出现问题的地方仅仅只是一个表现的地方并非深层次的原因因为内存问题相对比较复杂它是一个逐渐挤压的过程正好在你出现问题的代码那里爆了所以针对应用的内存问题开发者必须多加关注。 1.2 内存问题表现形式 内存抖动锯齿状、GC频繁导致卡顿 内存泄露可用内存逐渐减少、频繁GC 内存溢出OOM、程序异常 二、常用内存分析工具 要解决内存问题就必须要有强大的内存分析工具让我们更快更方便的定位内存问题。目前主流的内存分析工具主要有 LeakCanary、Memory Profiler、MAT。 2.1 LeakCanary LeakCanary是 Square 开源的一个内存泄露监控框架在应用运行时出现的内存泄露会被 LeakCanary 监控记录。 LeakCanary 内存泄漏的 trace 分析主要看 LeakingNO 到 LeakingYES 这段的 trace可以发现 TextView 出现了内存泄漏因为它持有了被销毁的 Activity 的上下文 Context。 更具体的 trace 分析具体可以查看官方文档 Fixing a memory leak。 使用 LeakCanary 虽然很方便但是也有一定弊端 直接引用依赖使用的 LeakCanary 一般用于线下调试应用发布到线上时需要关闭 应用调试时有时候会引起卡顿 所以 一般使用 LeakCanary 只是一种简便定位内存泄露的方式但如果需要更好的做内存优化比如定位内存抖动、Bitmap 优化等还是需要其他的分析工具主要常用的有 Memory Profiler 和 MAT。 2.2 NativeSize、Shallow Size、Retained Size、Depth 后续说明 Memory Profiler 和 MAT 时会经常出现几个比较重要的指标Shallow Size 和 Retained Size。在 Memory Profiler 还会提供 Native Size 和 Depth。 当您拿到一段 Heap Dump 之后Memory Profiler 会展示出类的列表。对于每个类Allocations 这一列显示的是它的实例数量。而在它右边则依次是 Native Size、Shallow Size 和 Retained Size 我们用下图来表示某段 Heap Dump 记录的应用内存状态。注意红色的节点在这个示例中这个节点所代表的对象从我们的工程中引用了 Native 对象这种情况不太常见但在 Android 8.0 之后使用 Bitmap 便可能产生此类情景因为 Bitmap 会把像素信息存储在原生内存中来减少 JVM 的内存压力。 先从 Shallow Size 讲起这列数据其实非常简单就是 对象本身消耗的内存大小 Depth 是从 GC Root 到达这个实例的最短路径图中的这些数字就是每个对象的深度 (Depth)。 一个对象离 GC Root 越近它就越有可能与 GC Root 有多条路径相连也就越可能在垃圾回收中被保存下来。 以红色节点为例如果从其左边来的任何一个引用被破坏红色节点就会变成不可访问的状态并且被垃圾回收回收掉。而对于右边的蓝色节点来说如果您希望它被垃圾回收那您需要把左右两边的路径都破坏才行。 值得警惕的是如果您看到某个实例的 Depth 为 1 的话这意味着它直接被 GC Root 引用同时也意味着它永远不会被自动回收。 下面是一个示例 Activity它实现了 LocationListener 接口高亮部分代码 requestLocationUpdates() 将会使用当前 Activity 实例来注册 locationManager。如果您忘记注销这个 Activity 就会泄漏。它将永远都待在内存里因为位置管理器是一个 GC Root而且永远都存在 您能在 Memory Profiler 中查看这一情况。点击一个实例Memory Profiler 将会打开一个面板来显示谁正在引用这个实例 我们可以看到位置管理器中的 mListener 正在引用这个 Activity。您可以更进一步通过引用面板导航至堆的引用视图它可以让您验证这条引用链是否是您所预期的也能帮您理解代码中是否有泄露以及哪里有泄露。 2.3 Memory Profiler Memory Profiler 是内置在 Android Studio 适用于查看实时内存情况 的内存分析工具。 2.3.1 Memory Profiler 界面说明 官方文档使用 Memory Profiler 查看 Java 堆和内存分配 2.3.2 Memory Profiler 查找内存抖动 查找内存抖动还是比较简单的运行的程序在 Memory Profiler 会呈现为在短时间内内存上下波动频繁触发 GC 回收。 内存抖动比较常见的地方 自定义View的 onMeasure()、onLayout()、onDraw() 直接 new 创建对象 列表比如 RecyclerView 的 onBindViewHolder() 直接 new 创建对象 有循环的代码中创建对象 用一个简单的案例模拟内存抖动 publicclassMainActivityextendsAppCompatActivity { ​SuppressWarnings(HandlerLeak)privateHandler mHandler newHandler() {OverridepublicvoidhandleMessage(Message msg) {// 模拟内存抖动for (int i 0; i 100; i) {String[] args newString[100000];} ​mHandler.sendEmptyMessageDelayed(0, 30);}}; ​OverrideprotectedvoidonCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); ​findViewById(R.id.button).setOnClickListener(newView.OnClickListener() {OverridepublicvoidonClick(View v) {mHandler.sendEmptyMessage(0);}});} } 复制代码 案例非常简单就是点击按钮时频繁的创建对象。在真机上运行上面的程序也许不会出现锯齿状的内存波动但是会有非常频繁的 GC 回收如下图 那应该怎么具体的定位到是哪里发生的内存抖动呢 按照上面的步骤操作 位置①在程序处于运行时点击 Record 按钮录制内存情况然后点击 Stop 停止录制会显示上图 位置②我们可以点击 Allocations 按降序从大到小或升序从小到大查看分配对象的数量一般我们会选择降序从大到小看数量最多的对象。上图对象数量最多的是 String 对象 位置③在 Instance View 随便选择一个 String 对象会显示下面的 Allocation Call Stack它会显示这个对象的调用栈位置 位置④ 从 Allocation Call Stack 可以看到String 对象是在 MainActivity 的第 18 行 handleMessage() 创建的从而也定位到内存抖动的位置 上面的操作还有一些小技巧 在位置①操作前为了排除干扰一般在录制前会先手动 GC 后再录制变化的内存在 Android 8.0 以上的设备可以实时的拖动 Memory Profiler 选择查看的内存波动范围 位置②上例是直接查看 Arrange by class但实际项目中更多的会是选择 Arrange by package 查看自己项目包名下的类 2.3.3 Memory Profiler 查找内存泄露 上面讲到内存泄露的表现是会出现内存抖动因为出现内存泄露时可用内存不断减少系统需要内存时获取内存不足就会 GC所以产生内存抖动。 出现内存泄露时 Memory Profiler 会呈现一个类似阶梯型的内存上升趋势而且内存没有降下来 上图的内存泄漏比较明显实际项目开发中出现内存泄漏时可能不会特别明显运行时间比较久才能发现内存是在缓慢上升的。这时候就需要 dump heap 帮助定位。 接下来会使用 Handler 内存泄露的案例简单讲解怎么使用 Memory Profiler 分析内存泄露。 public classHandlerLeakActivityextendsAppCompatActivity{private static finalStringTAG HandlerLeakActivity.class.getSimpleName(); ​privateHandler handler newHandler() {Overridepublic void handleMessage(Message msg) {if (msg.what 0) {Log.i(TAG, handler receive msg);}}}; ​Overrideprotected void onCreate(NullableBundle savedInstanceState) {super.onCreate(savedInstanceState);handler.sendEmptyMessageDelayed(0, 10 * 1000);} } 复制代码 上面代码非常简单就是启动 app 后每次进入 HandlerLeakActivity 就使用 Handler 延迟 10s 发送消息在 10s 内退出界面不断重复操作。 1、重复多次可能内存泄露的操作Memory Profiler 堆转储出 hprof 文件建议在操作前先 GC 排除干扰 2、在 Memory Profiler 查看查看堆转储文件 hprof 可以发现经过手动 GC 后Allocations 显示有 5 个 HandlerLeakActivity堆转储 Instance View 下也仍显示有多个 Activity 实例说明已经内存泄露具体的内存泄露定位可以在 Instance View 泄露的实例类对象中点击查看Instance View 下面的 Reference 会显示具体的引用链。 在新版本的 Memory Profiler 提供了 Activity/Fragment Leaks 复选框选中它可以直接找到可能内存泄露的位置 2.4 MAT 2.4.1 MAT简介 强大的Java Heap分析工具查找内存泄漏及内存占用 生成整体报告、分析问题等 线下深入使用 官网下载地址www.eclipse.org/mat/downloa… 这个地址是不是有你熟悉的单词嗯没错啦MAT是Eclipse中的一个插件因为现在开发过程中很多人都使用了IDEA或者Android Studio所以你不想下载Eclipse的话呢你可以去下载MAT的独立版解压之后里面有一个MemoryAnalyzer.exe的可执行文件直接点击就可以使用了。 这个工具很多时候我们需要结合Android Studio的堆转储能力配合使用但是需要注意AS3.0之后生成的hprof文件不是标准的hprof文件了需要使用命令转换一下hprof-conv 原文件路径 转换后文件路径 2.4.2 MAT用法简介 ①、Overview概览信息 Top Consumers 通过图表展示出占用内存比较多的对象此栏在做降低内存占用时比较有帮助 Biggest Objects相对详细的信息 Leak Suspects 快速查看内存泄露的可疑点 ②、 Histogram:直方图 Class Name具体检索某一个类 Objects某一个具体的Class有多少实例 Shallow Heap某单一实例自己占了多少内存 Retained Heap在这个引用链之上这些对象总共占了多少内存 Group by packge将类对象以包名形式展示 List objects with outgoing references:自身引用了哪些类 with incoming references自身被哪些类引用 ③、dominator_tree 每个对象的支配树 percentage:占所有对象的百分比 在条目上右键它也有List objects它和Histogram之间有啥区别呢主要区别就是下面两点 Histogram基于类的角度分析 dominator_tree基于实例的角度分析 ④、OQL对象查询语言类似于从数据库中检索内容 ⑤、thread_overview详细的展示线程信息可以查看出当前内存中存在多少线程 三、实战内存抖动解决 3.1 内存抖动简介 定义内存频繁分配和回收导致内存不稳定 表现频繁GC、内存曲线呈锯齿状 危害导致卡顿、严重时会导致OOM 3.2 内存抖动导致OOM 频繁创建对象导致内存不足及碎片不连续 不连续的内存片无法被分配导致OOM 3.3 实战分析 这一部分我会模拟一次内存抖动并通过Profiler分析内存情况定位到具体内存抖动的代码。 首先先来创建一个布局文件activity_memory.xml里面就一个按钮用来触发模拟内存抖动的那部分代码 ?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:orientationvertical android:layout_widthmatch_parentandroid:layout_heightmatch_parentButtonandroid:idid/btn_memoryandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text模拟内存抖动/ /LinearLayout 复制代码 然后定义一个MemoryShakeActivity页面加载刚才的布局并且在页面中定义一个Handler当点击模拟内存抖动的按钮时我们定时执行handleMessage中的模拟抖动的代码整个代码都是很容易能看懂的那种 /*** 说明模拟内存抖动页面*/publicclassMemoryShakeActivityextendsAppCompatActivityimplementsView.OnClickListener {SuppressLint(HandlerLeak)privatestaticHandler mHandler newHandler(){OverridepublicvoidhandleMessage(NonNull Message msg) {super.handleMessage(msg);//模拟内存抖动的场景每隔10毫秒执行一次循环执行100次每次通过new分配大内存for (int i0;i100;i){String[] obj newString[100000];}mHandler.sendEmptyMessageDelayed(0,10);}};OverrideprotectedvoidonCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_memory);findViewById(R.id.btn_memory).setOnClickListener(this);}OverridepublicvoidonClick(View view) {if (view.getId() R.id.btn_memory){mHandler.sendEmptyMessage(0);}}OverrideprotectedvoidonDestroy() {super.onDestroy();mHandler.removeCallbacksAndMessages(null);} } 复制代码 然后跑起来我截了两张图给大家看一下第一张是没有执行模拟抖动的代码之前的第二张是执行之后的 从上面两张图中可以清晰的看到第一张内存比较平稳第二张内存图有锯齿状出现突然出现了频繁的GC看到下面好多小垃圾桶了没这个时候可以初步判定应该是出现了内存抖动现象因为比较符合它的特征然后在面板上拖动一段距离它就会将这段时间内的内存分配情况给我们展示出来 首先双击Allocations然后将这一列按照从大到小的顺序排列好然后你会发现String数组居然有这么多它占用的内存大小也是最高的值得关注的点我都用矩形标出了此时我们就应该锁定这个目标为什么String类型的数组会有这么多这里很有可能是有问题的。然后排查究竟是哪里导致的这个问题很简单点击String[]这一行在右侧Instance View面板中随便点击一行下方Allocation Call Stack面板中就出现了对应的堆栈信息上面也列出了具体哪个类的哪一行右键jupm to source就可以跳转到指定的源码位置这样就找到了内存抖动出现的位置然后我们分析代码作相应的修改即可。 流程总结 使用Memory Profiler初步排查 使用Memory Profiler或CPU Profiler结合代码排查 内存抖动解决技巧找循环或者频繁调用的地方 四、实战内存泄露解决 4.1 内存泄露简介 定义内存中存在已经没有用的对象 表现内存抖动、可用内存逐渐变少 危害内存不足、GC频繁、OOM 4.2 实战分析 这里还是通过代码来真实的模拟一次内存泄露的场景对于一般的APP程序来说最大的问题往往都是在Bitmap上因为它消耗的内存比较多拿它来模拟会看的比较明显。好首先来看布局文件activity_memoryleak.xml里面就一个ImageView控件 ?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticalImageViewandroid:idid/iv_memoryleakandroid:layout_width50dpandroid:layout_height50dp / /LinearLayout 复制代码 然后定义了一个模拟处理某些业务的Callback回调接口和一个统一管理这些回调接口的Manager类 //模拟回调处理某些业务场景publicinterfaceCallBack {voiddpOperate(); }//统一管理CallbackpublicclassCallBackManager {publicstatic ArrayListCallBack sCallBacks new ArrayList();publicstaticvoidaddCallBack(CallBack callBack) {sCallBacks.add(callBack);}publicstaticvoidremoveCallBack(CallBack callBack) {sCallBacks.remove(callBack);} } 复制代码 然后在我们的模拟内存泄露的页面上设置Bitmap并设置回调监听 /*** 说明模拟内存泄露页面*/ public classMemoryLeakActivityextendsAppCompatActivityimplementsCallBack{Overrideprotected void onCreate(NullableBundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_memoryleak);ImageView imageView findViewById(R.id.iv_memoryleak);Bitmap bitmap BitmapFactory.decodeResource(getResources(), R.mipmap.big_bg);imageView.setImageBitmap(bitmap);CallBackManager.addCallBack(this);}Overridepublic void dpOperate() {} } 复制代码 OK我们的代码就写完了现在来实际运行一下然后将这个页面连续打开关闭多次看看这段代码会不会造成内存泄露呢 这是我用Profiler截取的内存图片可以看到整个内存在经过了我的反复开关页面之后虽然有的地方出现了一个小抖动但是整体是呈阶梯状上升的可用内存在逐渐减少此时基本上可以断定这个界面出现了内存泄露。Profiler工具虽然可以初步帮我们断定出现了内存泄露但是它却无法断定具体是哪里出现了内存泄露意思就是我们还是不知道该修改哪里的代码所以此时需要用到强大的Java Heap工具了来有请MAT出场。 首先需要在Profiler中点击Dump Java Heap按钮使用堆转储功能转换成一个文件然后点击保存按钮将文件保存到本地目录下比如我这里保存为H盘中的memoryleak.hprof文件然后使用hprof-conv命令将其转换为标准的hprof文件我这里是转换后的名称是memoryleak_transed.hprof如下所示 然后打开MAT工具导入刚刚生成的转换后的文件 点击Histogram查看内存中所有存活的对象然后我们在Class Name中可以输入内容搜索想要查找的对象 然后可以看到该对象的具体信息以及数量和所占用的内存大小我这里发现内存中居然存在6个MemoryLeakActivity对象 然后右键List objects----with incoming references找到所有引向它的强引用 然后右键Path To GC Roots-----with all references将所有引用都计算在内然后算出来这个对象和GCRoot之间的路径 来看结果最后是到了sCallBacks这里而且它左下角有个小圆圈这就是我们真正要找的位置也就是说MemoryLeakActivity是被CallBackManager这个类的sCallBacks这个对象引用了 根据上面找的结果到代码中去找CallBackManager的sCallBacks看看这里究竟是做了什么引发的 publicstaticArrayListCallBack sCallBacks new ArrayList(); 复制代码 MemoryLeakActivity是被sCallBacks这个静态变量引用着由于被static关键字修饰的变量的生命周期是和App的整个生命周期一样长的所以当MemoryLeakActivity这个页面关闭时我们应该将变量的引用关系给释放掉否则就出现了上面的内存泄露的问题。所以解决这个问题也很简单了添加如下几行代码 OverrideprotectedvoidonDestroy() {super.onDestroy();CallBackManager.removeCallBack(this); } 复制代码 流程总结 使用Memory Profiler初步观察可用内存逐渐减少 通过Memory Analyzer结合代码确认 五、线上内存监控方案 线上内存问题最大的就是内存泄露对于内存抖动和内存溢出它们一般都和内存泄露导致的内存无法释放相关如果能够解决内存泄露则线上内存问题就会减少很多。线上内存监控其实还是比较困难的因为我们无法使用线下的这些工具来直观的发现分析问题。 5.1 常规方案 ①、设定场景线上Dump 比如你的App已经占用到单个App最大可用内存的较高百分比比如80%通过Debug.dumpHprofData()这行代码可以实现将当前内存信息转化为本地文件。 整个流程如下超过内存80%——内存Dump——回传文件注意文件可能很大保持在wifi状态回传——MAT手动分析 总结 Dump文件太大和对象数正相关可裁剪 上传失败率高、分析困难 ②、LeakCanary线上使用 LeakCanary带到线上 预设泄露怀疑点 发现泄露回传 总结 不适合所有情况必须预设怀疑点限制了全面性 分析比较耗时也容易OOM实践发现LeakCanary分析过程较慢很有可能自己在分析的过程中自身发生OOM 5.2 LeakCanary定制 预设怀疑点——》自动找怀疑点谁的内存占用大就怀疑谁大内存对象出现问题的概率更大 分析泄露链路慢(分析预设对象的每一个对象)——》分析Retain Size大的对象(减少它的分析工作量提高分析速度) 分析OOM(将内存堆栈生成的所有文件全部映射到内存中比较占用内存)——》对象裁剪不全部加载到内存 5.3 线上监控完整方案 待机内存、重点模块内存、OOM率 整体及重点模块GC次数、GC时间 增强的LeakCanary自动化内存泄露分析 六、内存优化技巧 优化大方向 内存泄露 内存抖动 Bitmap 优化细节 LargeHeap属性虽然有点耍流氓但还是应该向系统申请 onTrimMemory、onLowMemory系统给的低内存的回调可以根据不同的回调等级去处理一些逻辑 使用优化过的集合SparseArray 谨慎使用SharedPreference一次性load到内存中 谨慎使用外部库尽量选择经过大规模验证的外部库 业务架构设计合理加载的数据是你能用到的不浪费内存加载无用数据
http://www.sczhlp.com/news/197088/

相关文章:

  • 设计漂亮的网站企业网站制作开发
  • 延吉市建设厅网站毕设用别人网站做原型
  • 0基础做网站用什么语言网页页面设计工具
  • ROS 传感器模块的通用架构设计与跨中间件扩展实践
  • 替代传统FTP的系统:企业数字化转型新选择
  • 算法设计与分析作业
  • 需求分析论
  • metro网站模板在柬埔寨做网络销售推网站
  • 大庆建设银行网站wordpress 3.6.2
  • 自建网站定位国外 家具 网站模板
  • 有没有专门做教程的网站中国建设网站银行
  • 军事网站大全军事网陕西省建设厅注册中心网站
  • 怎么自己网站搜不到短视频seo排名
  • 学用mvc4做网站【郑州网站建设】
  • 网站改版方案流程北京做网站维护
  • 两学一做教育考试网站网站备案时长
  • 官方网站下载12306呼伦贝尔人才网官方网站入口
  • 那样的网站seo深圳网络推广
  • 做网站基础教程17网站一起做网店普
  • 广州网站建设公司推荐wordpress 新建php文件
  • 技术支持 网站建设极速建站网站模板
  • 南山做网站教程苏州优化外包
  • 网站建设的有什么需求专业的微网站哪家好
  • 简述网站主要流程网站不会更新文章
  • 专题网站建设方案北京京水建设集团有限公司网站
  • 在百度怎样建网站济宁百度推广开户
  • mvc3网站上传到空间福建省建设行业企业资质查询网站
  • 龙游住房和城乡建设局网站北京展览馆网站建设
  • 广州营销型网站建设费用wordpress小清新主题
  • 网站登录页面html模板百度人气榜排名