Oracle 物化视图快速刷新对性能的影响

一个表上存在物化视图日志和基于物化视图日志快速刷新的物化视图,如果对这个表进行DML操作,则Redolog产生量将翻数倍,并且执行时间加长,影响并发操作。

下面主要通过在Redolog产生量和执行时间上做对比:
DB Version:12.1.0.2.0
OS:CentOS 6.6

[oracle@ct6603 ~]$ sqlplus system/system

SQL*Plus: Release 12.1.0.2.0 Production on Sat Nov 5 17:11:31 2016

Copyright (c) 1982, 2014, Oracle.  All rights reserved.

Last Successful login time: Sat Nov 05 2016 17:11:12 +08:00

Connected to:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 – 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
#建测试表
SQL> create table tb_rowid tablespace users as select * from dba_objects;

Table created.
#记录时间
SQL> set timing on
#设定自动提交
SQL> set autocommit on
#跟踪统计信息
SQL> set autotrace on stat

#表tb_rowid上无物化视图日志
#插入9999笔记录,Redolog产生量1249324,耗时00:00:00.21
SQL> insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:00.21

Statistics
———————————————————-
         42  recursive calls
       1105  db block gets
        497  consistent gets
        508  physical reads
    1249324  redo size
        859  bytes sent via SQL*Net to client
        870  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#插入9999笔记录,Redolog产生量1248532,耗时00:00:00.17
SQL> insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:00.17

Statistics
———————————————————-
          4  recursive calls
       1087  db block gets
        324  consistent gets
        245  physical reads
    1248532  redo size
        861  bytes sent via SQL*Net to client
        870  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量4147948,耗时00:00:00.50
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:00.50

Statistics
———————————————————-
          9  recursive calls
      11277  db block gets
        225  consistent gets
        276  physical reads
    4147948  redo size
        861  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量4164704,耗时00:00:00.60
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:00.60

Statistics
———————————————————-
          3  recursive calls
      11293  db block gets
        319  consistent gets
        104  physical reads
    4164704  redo size
        863  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#更新9999笔记录,Redolog产生量2725824,耗时00:00:00.48
SQL> update tb_rowid set object_id=1 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:00.48

Statistics
———————————————————-
          8  recursive calls
      10233  db block gets
        548  consistent gets
        145  physical reads
    2725824  redo size
        863  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#更新9999笔记录,Redolog产生量957056,耗时00:00:00.13
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:00.13

Statistics
———————————————————-
          8  recursive calls
        294  db block gets
        548  consistent gets
          0  physical reads
     957056  redo size
        864  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#更新9999笔记录,Redolog产生量961224,耗时00:00:00.14
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:00.14

Statistics
———————————————————-
          1  recursive calls
        294  db block gets
        489  consistent gets
          0  physical reads
     961224  redo size
        864  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed

#表tb_rowid上有物化视图日志
#建物化视图日志
SQL> create  materialized view log on tb_rowid with rowid including new values;

Materialized view log created.

Elapsed: 00:00:00.34

#插入9999笔记录,Redolog产生量10905808,耗时00:00:03.73
SQL> insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:03.73

Statistics
———————————————————-
        176  recursive calls
      43316  db block gets
       1227  consistent gets
        104  physical reads
   10905808  redo size
        862  bytes sent via SQL*Net to client
        870  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         14  sorts (memory)
          0  sorts (disk)
       9999  rows processed

#插入9999笔记录,Redolog产生量11015104,耗时00:00:04.03
SQL> insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:04.03

Statistics
———————————————————-
         32  recursive calls
      42863  db block gets
       6438  consistent gets
          2  physical reads
   11015104  redo size
        865  bytes sent via SQL*Net to client
        870  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量11019692,耗时00:00:03.88
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:03.88

Statistics
———————————————————-
         43  recursive calls
      42877  db block gets
        572  consistent gets
         27  physical reads
   11019692  redo size
        865  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量11010468,耗时00:00:03.73
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:03.73

Statistics
———————————————————-
         18  recursive calls
      42846  db block gets
        592  consistent gets
          0  physical reads
   11010468  redo size
        865  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed

#更新9999笔记录,Redolog产生量16150340,耗时00:00:06.94
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:06.94

Statistics
———————————————————-
         51  recursive calls
      73132  db block gets
       1292  consistent gets
        109  physical reads
   16150340  redo size
        865  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
       9999  rows processed

#更新9999笔记录,Redolog产生量16078152,耗时00:00:07.19
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:07.19

Statistics
———————————————————-
         30  recursive calls
      91767  db block gets
       1160  consistent gets
          1  physical reads
   16078152  redo size
        865  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
       9999  rows processed

#表tb_rowid上有快速刷新物化视图
#建物化视图mv_tb_rowid
SQL> create materialized view mv_tb_rowid tablespace users refresh fast on commit with rowid as select * from  tb_rowid;

Materialized view created.

Elapsed: 00:00:29.52

#插入9999笔记录,Redolog产生量20177192,耗时00:00:08.98
SQL> insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:08.98

Statistics
———————————————————-
       1415  recursive calls
      98178  db block gets
       4696  consistent gets
        412  physical reads
   20177192  redo size
        866  bytes sent via SQL*Net to client
        870  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         92  sorts (memory)
          0  sorts (disk)
       9999  rows processed
       
#插入9999笔记录,Redolog产生量19942160,耗时00:00:07.26
SQL>  insert into tb_rowid select * from tb_rowid where rownum<10000;

9999 rows created.

Commit complete.
Elapsed: 00:00:07.26

Statistics
———————————————————-
        223  recursive calls
      97346  db block gets
       7576  consistent gets
          1  physical reads
   19942160  redo size
        866  bytes sent via SQL*Net to client
        871  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         24  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量25751700,耗时00:00:08.75
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:08.75

Statistics
———————————————————-
        227  recursive calls
     136425  db block gets
       2362  consistent gets
          0  physical reads
   25751700  redo size
        866  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         24  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#删除9999笔记录,Redolog产生量25890548,耗时00:00:08.73
SQL> delete tb_rowid where rownum<10000;

9999 rows deleted.

Commit complete.
Elapsed: 00:00:08.73

Statistics
———————————————————-
        204  recursive calls
     136332  db block gets
       2223  consistent gets
        241  physical reads
   25890548  redo size
        868  bytes sent via SQL*Net to client
        842  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         22  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#更新9999笔记录,Redolog产生量42848860,耗时00:00:18.52
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:18.52

Statistics
———————————————————-
        902  recursive calls
     249586  db block gets
       5487  consistent gets
        292  physical reads
   42848860  redo size
        868  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         24  sorts (memory)
          0  sorts (disk)
       9999  rows processed
#更新9999笔记录,Redolog产生量43267360,耗时00:00:16.95
SQL> update tb_rowid set object_id=2 where rownum<10000;

9999 rows updated.

Commit complete.
Elapsed: 00:00:16.95

Statistics
———————————————————-
        215  recursive calls
     250097  db block gets
       4048  consistent gets
          0  physical reads
   43267360  redo size
        868  bytes sent via SQL*Net to client
        858  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         22  sorts (memory)
          0  sorts (disk)
       9999  rows processed
        
总结:
        表上无物化视图日志    表上有物化视图日志     表上有物化视图日志且有一个快速刷新的物化视图
插入        1M/0.21秒            10M/3.73秒                20M/8.98秒
删除        4M/0.5秒            10M/3.88秒                 25M/8.75秒
更新        1M/0.13秒            15M/6.94秒                40M/18.52秒

八年数据库之路的感悟

  时间过的很快,从在博客园写第一篇文章当现在刚好一年,而自己在数据库这条路上已经走过五年。回想下这五年感觉总是在【迷茫-激动-充实-迷茫-激动-充实】的循环中。本篇也分享一下这些迷茫激动充实和美好的愿景。

  古有大诗仙怀才不遇,诗书纵情于山水,今有小人物蓝瘦香菇,博文感悟与园友。

成长

  IT民工,程序猿,救火队,刚刚踏入IT界,这些词就早已经如雷贯耳,电脑坏了不会修?你是做IT的?

  抛开残酷的现实,寻找那最初的美好,每个人踏入这个行业从小白开始都会抱有成为一个称做“行业专家”的理想。

  我也不例外,刚刚毕业有过好多目标,写程序,做BI,业务设计,项目管理……就像熊瞎子劈苞米,劈一个扔一个,最后什么也没剩下!(好像现在的新同学会更有感触,因为现在的技术花样更多了)

  工作三年后,走过迷茫期,我坚定地选择了数据库DBA这条路,决定走下去并义无反顾。oracle科班出身的我,因为工作和自己的一点小兴趣选择了SQL Server。

 耐得住寂寞

  看书,学习的最基本途径,看不下去就抄!原理性的东西也许只能这样获取到(也可能是我比较笨),不断的学,模拟,思考。还记得《SQL Server 2005技术内幕》四本书,绝对是我的启蒙老师,至今仍然收藏,时不时拿起来翻看。

  这个过程很多人感觉特别枯燥,无法坚持。也许像我这样的人可能不太大众,我反而觉得这个过程特别的激动,每天都学到很多新东西又特别的充实。

 打破迷茫

  很多时候学习和数据库系统一样会遇到瓶颈,这样的瓶颈如果处理好,那么你就是阶段成长,跳到了下一个阶段,如果没处理好,就会打回原形(劈苞米一样)。

  迷茫主要有两点:

  •   很多东西理解不了,有没有地方去问
  •   没有实践的环境,工作不匹配,有很难找到匹配的

  对于第一点,我当时就是在CSDN各种发帖,各种问(现在看看当时的问题,我真是厉害了不少呢,哈哈)。了解这种痛苦,所以请同样有这种苦恼,问题不知道像谁请教的同学加QQ群:302593467(群里我拉了不少SQL Server大神呦)

  对于第二点,这个真的没什么办法,看机遇了。不过一个建议:想要理想往往会牺牲一些(我的第一个数据库DBA相关工作比开发时工资少了一半)。当有一个实践的场景你的基础理论会大幅发挥出来,技能提升特别快。这就是传说中的一张窗户纸。

独当一面

  刚工作,给自己定了一个称做“行业专家”的理想,而期限是五年,而所谓的行业专家其实也只是能够在一个领域或技能上独当一面。在工作五年的时候基本上达到了我的预期,这个时候大部分的数据库问题我能够独立解决,出现问题也能理性的思考,并且慢慢整理思路不断学习。

  激动的感觉,满足的感觉。

 再次迷茫

  程序猿的悲催在于活到老学到老,不能停下学习的脚步。这个时候在一个技能(SQL Server)的学习上,自己感觉不到那种突飞猛进的感觉,很多时候学习都是需要真实的遇到场景,踩过坑才能在坑中学习。而在一个公司当DBA总是维护着自己的系统,根本没有那么多坑去踩。很长的一段迷茫期不知道怎么办,所以我尝试了学习新东西,比如mysql,大数据相关的,甚至学习销售、营销等,但是我依然迷茫,不知要怎么走下一步。

 偶然的机遇

  这也是我现在的公司,做SQL Server技术支持,在这里我遇到了很多志同道合的人,这里我们都是SQL Server技术的爱好者,一起研究技术,一起帮用户解决问题,这也让我自己意识到自己的很多很多不足,写了一年的博客不少人称我为大神,虽然有些小高兴,但内心我只能苦笑,因为我知道,凭借我的技术水平在公司的技术团队里,不是倒数第一也是倒数第二。

  但也正是有这样的机遇让我重新找到了方向,找到了一起奋斗的伙伴,也燃起了斗志。

 

技术支持的感悟

  因为做技术支持的工作,所以每天都能接触到不同的客户,他们有着这样活那样的数据库问题。对于我又像进入了一个新世界,这里一切都是那么不一样。

 迷茫又至

  刚刚到公司,处理客户问题的时候总是打了鸡血一样,充满了激情,对于客户问题总是耐心讲解,甚至深入到原理,表、索引存储结构,为什么会出现这样的问题等等。但是时间长了,我发现很多客户的问题都是大同小异,很多客户的运维人员都是一知半解,甚至连什么是日志备份都不知道。

 气愤

  很多时候不明白,为什么你维护的系统存在这样那样的问题,而你作为运维人员却完全不知道呢?上TB的数据库,而且不能有数据丢失,却只是简单恢复模式呢?为什么告诉你数据库应该定期体检,监控问题,而你却无动于衷呢?为什么你认为数据库不会出现损坏问题?为什么你认为做了raid就不用备份数据库了?

 深深的思考

  为什么客户的数据库都是这样的?作为运维人员为什么不好好学一学呢?慢慢的我意识到了,问题基本可以归结成三类:

  • 人手有限,往往身兼数职(网管、项目管理、协调厂商、DBA、应用、写报告),既有很多协调性的管理工作,又有一些专业技术工作,尤其是数据库,短时间是很难深入掌握的。

  • 自己开发系统,擅长程序开发,对于数据库,了解的不深,更多的是业务逻辑,比如表结构设计、如何写存储过程等,导致后期很多业务存在性能瓶颈。
  • 买的软件厂商的,在他们的行业里,IT运维人员对系统进行的往往是简单维护,做的最多的是和业务功能相关的事情,很多数据库的专业问题困扰着他们,招聘资深数据库专家吧,人家不来,自己解决吧,又很吃力,寻求厂商,他们也没有好的方案,集成商就是换硬件。

 理解

  为什么会有DBA的存在,因为DBA是一群在数据库上精通的人,也可以说是数据库上的内行,而没有深入研究的就可以理解为外行。内行给外行的建议就好比:医生建议你每天要吃蔬菜,这样身体的什么什么指标会正常,每天要吃什么什么这样会保证你身体怎么怎么好,同时要每天运动,运动能增强免疫力,减少得病的几率。

  而我呢,我自己呢?对于医生来说我是外行,那么医生给我的建议可能也得不到我的警醒和重视,只有到生病了(我比较坚强一般是病入膏肓)才会去医院看病。  

  同样作为数据库的技术支持,我会给客户提出的建议,而他们的反应就像医生给我建议时我的反应和应对一样。

  天天奔波忙碌的我也不可能静下心来,拿起一本医学原理来看看。

成人达己

  技术人员都带着一个改变世界的梦想,而我,没有那么大的梦,我(和我身边的一群人)只想让所有用SQL Server的用户,真正能把数据库用好,高效且平稳,想改变SQL Server在技术人员口中的评价。

  慢慢的我意识到,学习成长最大的乐趣就是能够帮助别人,并在这个过程中自我完善,还有那被称为大神的小喜悦。

  美好的愿景从点滴开始,我们团队也正在研发准备打造出一个免费的体检诊断平台(SQL专家云),这个平台属于所有IT运维人员,属于所有SQL Server的爱好者。让更多人能一起交流技术,让数据库运维变得简单,熟练既是效率,让天下没有难运维的数据库。

   

 总结

  成长过程到独当一面,到最终用自己的技能帮助尽可能多的人,也许这就是技术匠人的路吧。都说这个时代需要的是匠人,匠人精神,也许我某种程度上已经拥有了这样的精神。

  每天很累,做着必须干的事儿,这是为了生计。

  每天很累,做着不爱干的事儿,这是为了工作。

  每天很累,做着喜欢干的事儿,这是为了事业。

  每天很累,但却乐在其中,这是情怀。

————–博客地址—————————————————————————–

原文地址: http://www.cnblogs.com/double-K/

如有转载请保留原文地址! 

 

 —————————————————————————————————-

注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!

Android性能优化的浅谈

一、概要:

    本文主要以Android的渲染机制、UI优化、多线程的处理、缓存处理、电量优化以及代码规范等几方面来简述Android的性能优化

 

二、渲染机制的优化:

    大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能

    Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。

    Android性能优化的浅谈

    如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。

    Android性能优化的浅谈

    Probably:也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行 的次数过多。这些都会导致CPU或者GPU负载过重。

    Resolved:我们可以通过一些工具来定位问题,比如可以使用HierarchyViewer来查找Activity中的布局是否过于复杂,也可以使用手机设置里 面的开发者选项,打开Show GPU Overdraw等选项进行观察。

          你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能瓶颈。

    

    浅谈Overdraw(过度绘制):

      Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。 

      Android性能优化的浅谈

      Tips:我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,可以观察UI上的Overdraw情况

      Android性能优化的浅谈

      图解:蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。

      Tips:Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面 的Layout又有自己的背景,同时子View又分别有自己的背景。

      仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加 蓝色区域的占比。这一措施能够显著提升程序性能。

 

      注意:如需获取更多渲染机制的内容,请移步 https://www.oschina.net/news/60157/android-performance-patterns

 

三、UI方面的优化:

     1)首先简单谈谈view的绘制流程:measure – layout – draw

     Android性能优化的浅谈

      ps:具体的流程网上一搜一大把+_+

     2)子控件越多,绘制的时间也就越长。

      对于Listview或者GridView这种多item的组件来说,复用item可以减少inflate次数,通过setTaggetTagViewHolder方式实现复用,这里要注意的是,holder中的控件最好reset后再赋值,避免图片,文字错乱。

      *以下简单的例子:(尽量使用注解,有很多注解的开源框架可以使用:butterKnife, AndroidAnnotation, Dragger2

 1 static class ViewHolder{
 2     @InjectView(R.id.imageView1)
 3     ImageView imageView1;
 4     @InjectView (R.id.text1)
 5     TextView textView1;
 6 }
 7 
 8 @Override
 9 public View getView(int position, View convertView, ViewGroup parent) {
10     ViewHolder holder;
11              
12     if(convertView == null){
13        holder = new ViewHolder();
14        convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_item, null);
15        convertView.setTag(holder);
16      }else{
17          holder = (ViewHolder)convertView.getTag();
18      }
19              
20          holder.imageView1.setImageResource(R.drawable.ic_launcher);
21          holder.textView1.setText(mData.get(position));  
22              
23          return convertView;
24 }

    3)UI ReView(视图的检查) 

      1. 减少视图层级可以有效的减少内存消耗,因为视图是一个树形结构,每次刷新和渲染都会遍历一次。

      2. 想要减少视图层级首先就需要知道视图层级,所以下面介绍一个SDK中自带的一个非常好用的工具hierarchyviewer。你可以在下面的地址找到它:your sdk path/sdk/tools

      Android性能优化的浅谈

      3. 如上图大家可以看到,hierarchyviewer可以非常清楚的看到当前视图的层级结构,并且可以查看视图的执行效率(视图上的小圆点,绿色表示流畅,黄色和红色次之),所以我们可以很方便的查看哪些view可能会影响我们的性能从而去进一步优化它。

       hierarchyviewer还提供另外一种列表式的查看方式,可以查看详细的屏幕画面,具体到像素级别的问题都可以通过它发现。

       

      4)一些标签的使用

      <merge>它在优化UI结构时起到很重要的作用。目的是通过删减多余或者额外的层级,从而优化整个Android Layout的结构,优化布局层数。

      <include >可以通过这个标签直接加载外部的xml到当前结构中,是复用UI资源的常用标签,来共享布局。

      <ViewStub>动态加载view,此标签可以使UI在特殊情况下,直观效果类似于设置View的不可见性,但是其更大的意义在于被这个标签所包裹的Views在默认状态下不会占用任何内存空间。

 

四、多线程的处理:

   1. Android 提供的多种多线程工具类 (AsyncTask, HandlerThread, IntentService, ThreadPool),许多操作都需要由 主线程(UI 线程)来执行,比如:

      Android性能优化的浅谈

      2. Android 系统的屏幕刷新频率为 60 fps, 也就是每隔 16 ms 刷新一次。如果在某次绘制过程中,我们的操作不能在 16 ms 内完成,那它则不能赶上这次的绘制公交车,只能等下一轮。

       这种现象叫做 “掉帧”,用户看到的就是界面绘制不连续、卡顿。

      Android性能优化的浅谈

      3. HandlerThread 就是MessageQueue,Looper和 Handler 的组合。每个应用启动时,系统会创建一个该应用的进程以及主线程,这里的主线程就是一个 HandlerThread。

      Android性能优化的浅谈

      4. 注意问题:

       1)多线程并发访问资源要遵循重要的原则就是 原子性、可见性、有序性。没有同步机制的情况下,多个线程同时读写内存可能会导致意料之外的问题:

       线程安全的问题; ② UI 组件的生命周期并不确定;线程引用导致的内存泄漏问题

          2)不要在任何子线程持有 UI 组件或者 Activity 的引用

       3)保持响应不发生ANR: 

        ①从UI线程中移除费时操作这个方式还可以防止用户操作出现系统不响应(ANR)对话框。需要做的就是继承AsyncTask来创建一个后台工作线程,并实现doInBackground()方法。

        ②还有一种方式就是自己创建一个Thread类或者HandlerThread类,明确设定线程的优先级。

       4)使用StrictMode来检查UI线程中可能潜在的费时操作,使用一些特殊的工具如Safe.ijiamiSystrace或者Traceview来寻找在你的应用中的瓶颈;用进度条向用户展示操作进度。

 

五、缓存处理:

  简单的说说缓存优化的几个方面:

    缓存机制网络+数据库。为了避免从网络获取重复的数据,可以在activity或者fragment或者每个组件设置一个最大请求间隔。

        比如一个listview,第一次请求数据时,保存一份到数据库,并记下时间戳,当下次重新初始化时,判断是否超过最大时间间隔(5分钟),如果没有,只加载数据库数据,不需要再做网络请求。

        (当然,还有一些隐式的http请求框架会缓存服务器数据,在一定时间内不再请求网络,或者当服务器返回304时将之前缓存的数据直接返回)

 

 

   网络方面:1)需要服务端配合的:json数据格式,WebP代替jpg,支持断点续传,多个请求合并成一个,尽量不做重定向,服务器缓存以及负载均衡等。

        2)对客户端本身,除了上述的实现,我们还需要合理的缓存,控制最大请求并发量,及时取消已失效的请求,过滤重复请求,timeout时间设置,请求优先级设置等。

         

        * WebP:WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;

             同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG PNG 上的转化效果都相当优秀、稳定和统一。

             Android性能优化的浅谈

               转换后的 WebP 支持 Alpha 透明和 24-bit 颜色数,不存在 PNG8 色彩不够丰富和在浏览器中可能会出现毛边的问题。

              * 更多了解请看:http://isux.tencent.com/introduction-of-webp.html

 

 

 六、电量优化:

     有下面一些措施能够显著减少电量的消耗:

      • 我们应该尽量减少唤醒屏幕的次数与持续的时间,使用WakeLock来处理唤醒的问题,能够正确执行唤醒操作并根据设定及时关闭操作进入睡眠状态。

      • 某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行。

      • 触发网络请求的操作,每次都会保持无线信号持续一段时间,我们可以把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗。

        关于网络请求引起无线信号的电量消耗,还可以参考这里http://hukai.me/android-training-course-in-chinese/connectivity/efficient-downloads/efficient-network-access.html

    Android性能优化的浅谈

 

    Ask:假设你的手机里面装了大量的社交类应用,即使手机处于待机状态,也会经常被这些应用唤醒用来检查同步新的数据信息。

    Android会不断关闭各种硬 件来延长手机的待机时间,首先屏幕会逐渐变暗直至关闭,然后CPU进入睡眠,这一切操作都是为了节约宝贵的电量资源。但是即使在这种睡眠状态下,大多数应 用还是会尝试进行工作,他们将不断的唤醒手机。

    一个最简单的唤醒手机的方法是使用PowerManager.WakeLock的API来保持CPU工作并 防止屏幕变暗关闭。这使得手机可以被唤醒,执行工作,然后回到睡眠状态。知道如何获取WakeLock是简单的,可是及时释放WakeLock也是非常重 要的。

    不恰当的使用WakeLock会导致严重错误。例如网络请求的数据返回时间不确定,导致本来只需要10s的事情一直等待了1个小时,这样会使得电量 白白浪费了。这也是为何使用带超时参数的wakelock.acquice()方法是很关键的。

    但是仅仅设置超时并不足够解决问题,例如设置多长的超时比 较合适?什么时候进行重试等等?

 

    Resolved:解决上面的问题,正确的方式可能是使用非精准定时器。通常情况下,我们会设定一个时间进行某个操作,但是动态修改这个时间也许会更好。

    例如,如果有 另外一个程序需要比你设定的时间晚5分钟唤醒,最好能够等到那个时候,两个任务捆绑一起同时进行,这就是非精确定时器的核心工作原理。我们可以定制计划的 任务,可是系统如果检测到一个更好的时间,它可以推迟你的任务,以节省电量消耗。

    Android性能优化的浅谈

    * 关于JobScheduler的更多知识可以参考 http://hukai.me/android-training-course-in-chinese/background-jobs/scheduling/index.html

 

 七、代码规范

  

    1for loop中不要声明临时变量,不到万不得已不要在里面写try catch

    2)明白垃圾回收机制,避免频繁GC,内存泄漏,OOM(有机会专门说)

    3)合理使用数据类型,StringBuilder代替String,少用枚举enum,少用父类声明(List,Map)

    4)如果你有频繁的new线程,那最好通过线程池去execute它们,减少线程创建开销。

    5)你要知道单例的好处,并正确的使用它。

    6)多用常量,少用显式的“action_key”,并维护一个常量类,别重复声明这些常量。

    7)如果可以,至少要弄懂设计模式中的策略模式,组合模式,装饰模式,工厂模式,观察者模式,这些能帮助你合理的解耦,即使需求频繁变更,你也不用害怕牵一发而动全身。需求变更不可怕,可怕的是没有在写代码之前做合理的设计。

    8)View中设置缓存属性.setDrawingCachetrue.

    9)cursor 的使用。不过要注意管理好cursor,不要每次打开关闭cursor.因为打开关闭Cursor非常耗时。 Cursor.require用于刷cursor.

    10)采用SurfaceView在子线程刷新UI, 避免手势的处理和绘制在同一UI线程(普通View都这样做)

    11)采用JNI,将耗时间的处理放到c/c++层来处理

    12)有些能用文件操作的,尽量采用文件操作,文件操作的速度比数据库的操作要快10倍左右

    13)懒加载和缓存机制。访问网络的耗时操作启动一个新线程来做,而不要再UI线程来做

    14)如果方法用不到成员变量,可以把方法申明为static,性能会提高到15%20%

    15)避免使用getter/setter存取field,可以把field申明为public,直接访问

    16)私有内部类要访问外部类的field或方法时,其成员变量不要用private,因为在编译时会生成setter/getter,影响性能。可以把外部类的field或方法声明为包访问权限

    17)合理利用浮点数,浮点数比整型慢两倍

    18)针对ListView的性能优化,ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。ListViewgetView是性能是关键,这里要尽可能的优化。

       getView方法中要重用viewgetView方法中不能做复杂的逻辑计算,特别是数据库操作,否则会严重影响滑动时的性能

    19)不用new关键词创建类的实例,用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。

      clone()方法不会调用任何类构造函数。在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实例非常简单。例如,下面是Factory模式的一个典型实现:

    20)public static Credit getNewCredit() {
            return new Credit();
      }
      改进后的代码使用clone()方法,如下所示:
      private static Credit BaseCredit = new Credit();
            public static Credit getNewCredit() {
                  return (Credit) BaseCredit.clone();
            }
    上面的思路对于数组处理同样很有用。

    21)乘法和除法

      考虑下面的代码:

    1. for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
      用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码:
      for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

    22)ViewPager同时缓存page数最好为最小值3,如果过多,那么第一次显示时,ViewPager所初始化的pager就会很多,这样pager累积渲染耗时就会增多,看起来就卡。

    23)每个pager应该只在显示时才加载网络或数据库(UserVisibleHint=true),最好不要预加载数据,以免造成浪费

     24)提高下载速度:要控制好同时下载的最大任务数,同时给InputStream再包一层缓冲流会更快(BufferedInputStream)

    25)提供加载速度:让服务端提供不同分辨率的图片才是最好的解决方案。还有合理使用内存缓存,使用开源的框架