精华内容
下载资源
问答
  • Android性能优化典范

    千次阅读 2015-09-11 20:57:22
    转自:http://hukai.me/android-performance-patterns/2015新年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App。课程专题不仅仅介绍了...

    转自:http://hukai.me/android-performance-patterns/

    2015新年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App。课程专题不仅仅介绍了Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问题以及提升性能的建议。主要从三个方面展开,Android的渲染机制,内存与GC,电量优化。下面是对这些问题和建议的总结梳理。

    0)Render Performance

    大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。

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

    用户容易在UI执行动画或者滑动ListView的时候感知到卡顿不流畅,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原因可以导致丢帧,也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行的次数过多。这些都会导致CPU或者GPU负载过重。

    我们可以通过一些工具来定位问题,比如可以使用HierarchyViewer来查找Activity中的布局是否过于复杂,也可以使用手机设置里面的开发者选项,打开Show GPU Overdraw等选项进行观察。你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能瓶颈。

    1)Understanding Overdraw

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

    当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用越来越多的层叠组件来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽量减少Overdraw的情况发生。

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

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

    Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。

    2)Understanding VSYNC

    为了理解App是如何进行渲染的,我们必须了解手机硬件是如何工作,那么就必须理解什么是VSYNC

    在讲解VSYNC之前,我们需要了解两个相关的概念:

    • Refresh Rate:代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如60Hz。
    • Frame Rate:代表了GPU在一秒内绘制操作的帧数,例如30fps,60fps。

    GPU会获取图形数据进行渲染,然后硬件负责把渲染后的内容呈现到屏幕上,他们两者不停的进行协作。

    不幸的是,刷新频率和帧率并不是总能够保持相同的节奏。如果发生帧率与刷新频率不一致的情况,就会容易出现Tearing的现象(画面上下两部分显示内容发生断裂,来自不同的两帧数据发生重叠)。

    理解图像渲染里面的双重与三重缓存机制,这个概念比较复杂,请移步查看这里:http://source.android.com/devices/graphics/index.html,还有这里http://article.yeeyan.org/view/37503/304664

    通常来说,帧率超过刷新频率只是一种理想的状况,在超过60fps的情况下,GPU所产生的帧数据会因为等待VSYNC的刷新信息而被Hold住,这样能够保持每次刷新都有实际的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。

    在这种情况下,某些帧显示的画面内容就会与上一帧的画面相同。糟糕的事情是,帧率从超过60fps突然掉到60fps以下,这样就会发生LAGJANKHITCHING等卡顿掉帧的不顺滑的情况。这也是用户感受不好的原因所在。

    3)Tool:Profile GPU Rendering

    性能问题如此的麻烦,幸好我们可以有工具来进行调试。打开手机里面的开发者选项,选择Profile GPU Rendering,选中On screen as bars的选项。

    选择了这样以后,我们可以在手机画面上看到丰富的GPU绘制图形信息,分别关于StatusBar,NavBar,激活的程序Activity区域的GPU Rending信息。

    随着界面的刷新,界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。

    中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。

    每一条柱状线都包含三部分,蓝色代表测量绘制Display List的时间,红色代表OpenGL渲染Display List所需要的时间,黄色代表CPU等待GPU处理的时间。

    4)Why 60fps?

    我们通常都会提到60fps与16ms,可是知道为何会是以程序是否达到60fps来作为App性能的衡量标准吗?这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。

    12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。但是低于30fps是无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,当然超过60fps是没有必要的。

    开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理所有的任务。

    5)Android, UI and the GPU

    了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。那么一个最实际的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是如何能够被识别并绘制出来的?

    Resterization栅格化是绘制那些Button,Shape,Path,String,Bitmap等组件最基础的操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就是为了加快栅格化的操作。

    CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。

    然而每次从CPU转移到GPU是一件很麻烦的事情,所幸的是OpenGL ES可以把那些需要渲染的纹理Hold在GPU Memory里面,在下次需要渲染的时候直接进行操作。所以如果你更新了GPU所hold住的纹理内容,那么之前保存的状态就丢失了。

    在Android里面那些由主题所提供的资源,例如Bitmaps,Drawables都是一起打包到统一的Texture纹理当中,然后再传递到GPU里面,这意味着每次你需要使用这些资源的时候,都是直接从纹理里面进行获取渲染的。当然随着UI组件的越来越丰富,有了更多演变的形态。例如显示图片的时候,需要先经过CPU的计算加载到内存中,然后传递给GPU进行渲染。文字的显示更加复杂,需要先经过CPU换算成纹理,然后再交给GPU进行渲染,回到CPU绘制单个字符的时候,再重新引用经过GPU渲染的内容。动画则是一个更加复杂的操作流程。

    为了能够使得App流畅,我们需要在每一帧16ms以内处理完所有的CPU与GPU计算,绘制,渲染等等操作。

    6)Invalidations, Layouts, and Performance

    顺滑精妙的动画是app设计里面最重要的元素之一,这些动画能够显著提升用户体验。下面会讲解Android系统是如何处理UI组件的更新操作的。

    通常来说,Android需要把XML布局文件转换成GPU能够识别并绘制的对象。这个操作是在DisplayList的帮助下完成的。DisplayList持有所有将要交给GPU绘制到屏幕上的数据信息。

    在某个View第一次需要被渲染时,DisplayList会因此而被创建,当这个View要显示到屏幕上时,我们会执行GPU的绘制指令来进行渲染。如果你在后续有执行类似移动这个View的位置等操作而需要再次渲染这个View时,我们就仅仅需要额外操作一次渲染指令就够了。然而如果你修改了View中的某些可见组件,那么之前的DisplayList就无法继续使用了,我们需要回头重新创建一个DisplayList并且重新执行渲染指令并更新到屏幕上。

    需要注意的是:任何时候View中的绘制内容发生变化时,都会重新执行创建DisplayList,渲染DisplayList,更新到屏幕上等一系列操作。这个流程的表现性能取决于你的View的复杂程度,View的状态变化以及渲染管道的执行性能。举个例子,假设某个Button的大小需要增大到目前的两倍,在增大Button大小之前,需要通过父View重新计算并摆放其他子View的位置。修改View的大小会触发整个HierarcyView的重新计算大小的操作。如果是修改View的位置则会触发HierarchView重新计算其他View的位置。如果布局很复杂,这就会很容易导致严重的性能问题。我们需要尽量减少Overdraw。

    我们可以通过前面介绍的Monitor GPU Rendering来查看渲染的表现性能如何,另外也可以通过开发者选项里面的Show GPU view updates来查看视图更新的操作,最后我们还可以通过HierarchyViewer这个工具来查看布局,使得布局尽量扁平化,移除非必需的UI组件,这些操作能够减少Measure,Layout的计算时间。

    7)Overdraw, Cliprect, QuickReject

    引起性能问题的一个很重要的方面是因为过多复杂的绘制操作。我们可以通过工具来检测并修复标准UI组件的Overdraw问题,但是针对高度自定义的UI组件则显得有些力不从心。

    有一个窍门是我们可以通过执行几个APIs方法来显著提升绘制操作的性能。前面有提到过,非可见的UI组件进行绘制更新会导致Overdraw。例如Nav Drawer从前置可见的Activity滑出之后,如果还继续绘制那些在Nav Drawer里面不可见的UI组件,这就导致了Overdraw。为了解决这个问题,Android系统会通过避免绘制那些完全不可见的组件来尽量减少Overdraw。那些Nav Drawer里面不可见的View就不会被执行浪费资源。

    但是不幸的是,对于那些过于复杂的自定义的View(重写了onDraw方法),Android系统无法检测具体在onDraw里面会执行什么操作,系统无法监控并自动优化,也就无法避免Overdraw了。但是我们可以通过canvas.clipRect()来帮助系统识别那些可见的区域。这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视。这个API可以很好的帮助那些有多组重叠组件的自定义View来控制显示的区域。同时clipRect方法还可以帮助节约CPU与GPU资源,在clipRect区域之外的绘制指令都不会被执行,那些部分内容在矩形区域内的组件,仍然会得到绘制。

    除了clipRect方法之外,我们还可以使用canvas.quickreject()来判断是否没和某个矩形相交,从而跳过那些非矩形区域内的绘制操作。做了那些优化之后,我们可以通过上面介绍的Show GPU Overdraw来查看效果。

    8)Memory Churn and performance

    虽然Android有自动管理内存的机制,但是对内存的不恰当使用仍然容易引起严重的性能问题。在同一帧里面创建过多的对象是件需要特别引起注意的事情。

    Android系统里面有一个Generational Heap Memory的模型,系统会根据内存中不同的内存数据类型分别执行不同的GC操作。例如,最近刚分配的对象会放在Young Generation区域,这个区域的对象通常都是会快速被创建并且很快被销毁回收的,同时这个区域的GC操作速度也是比Old Generation区域的GC操作速度更快的。

    除了速度差异之外,执行GC操作的时候,所有线程的任何操作都会需要暂停,等待GC操作完成之后,其他操作才能够继续运行。

    通常来说,单个的GC并不会占用太多时间,但是大量不停的GC操作则会显著占用帧间隔时间(16ms)。如果在帧间隔时间里面做了过多的GC操作,那么自然其他类似计算,渲染等操作的可用时间就变得少了。

    导致GC频繁执行有两个原因:

    • Memory Churn内存抖动,内存抖动是因为大量的对象被创建又在短时间内马上被释放。
    • 瞬间产生大量的对象会严重占用Young Generation的内存区域,当达到阀值,剩余空间不够的时候,也会触发GC。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。

    解决上面的问题有简洁直观方法,如果你在Memory Monitor里面查看到短时间发生了多次内存的涨跌,这意味着很有可能发生了内存抖动。

    同时我们还可以通过Allocation Tracker来查看在短时间内,同一个栈中不断进出的相同对象。这是内存抖动的典型信号之一。

    当你大致定位问题之后,接下去的问题修复也就显得相对直接简单了。例如,你需要避免在for循环里面分配对象占用内存,需要尝试把对象的创建移到循环体之外,自定义View中的onDraw方法也需要引起注意,每次屏幕发生绘制以及动画执行过程中,onDraw方法都会被调用到,避免在onDraw方法里面执行复杂的操作,避免创建对象。对于那些无法避免需要创建对象的情况,我们可以考虑对象池模型,通过对象池来解决频繁创建与销毁的问题,但是这里需要注意结束使用之后,需要手动释放对象池中的对象。

    9)Garbage Collection in Android

    JVM的回收机制给开发人员带来很大的好处,不用时刻处理对象的分配与回收,可以更加专注于更加高级的代码实现。相比起Java,C与C++等语言具备更高的执行效率,他们需要开发人员自己关注对象的分配与回收,但是在一个庞大的系统当中,还是免不了经常发生部分对象忘记回收的情况,这就是内存泄漏。

    原始JVM中的GC机制在Android中得到了很大程度上的优化。Android里面是一个三级Generation的内存模型,最近分配的对象会存放在Young Generation区域,当这个对象在这个区域停留的时间达到一定程度,它会被移动到Old Generation,最后到Permanent Generation区域。

    每一个级别的内存区域都有固定的大小,此后不断有新的对象被分配到此区域,当这些对象总的大小快达到这一级别内存区域的阀值时,会触发GC的操作,以便腾出空间来存放其他新的对象。

    前面提到过每次GC发生的时候,所有的线程都是暂停状态的。GC所占用的时间和它是哪一个Generation也有关系,Young Generation的每次GC操作时间是最短的,Old Generation其次,Permanent Generation最长。执行时间的长短也和当前Generation中的对象数量有关,遍历查找20000个对象比起遍历50个对象自然是要慢很多的。

    虽然Google的工程师在尽量缩短每次GC所花费的时间,但是特别注意GC引起的性能问题还是很有必要。如果不小心在最小的for循环单元里面执行了创建对象的操作,这将很容易引起GC并导致性能问题。通过Memory Monitor我们可以查看到内存的占用情况,每一次瞬间的内存降低都是因为此时发生了GC操作,如果在短时间内发生大量的内存上涨与降低的事件,这说明很有可能这里有性能问题。我们还可以通过Heap and Allocation Tracker工具来查看此时内存中分配的到底有哪些对象。

    10)Performance Cost of Memory Leaks

    虽然Java有自动回收的机制,可是这不意味着Java中不存在内存泄漏的问题,而内存泄漏会很容易导致严重的性能问题。

    内存泄漏指的是那些程序不再使用的对象无法被GC识别,这样就导致这个对象一直留在内存当中,占用了宝贵的内存空间。显然,这还使得每级Generation的内存区域可用空间变小,GC就会更容易被触发,从而引起性能问题。

    寻找内存泄漏并修复这个漏洞是件很棘手的事情,你需要对执行的代码很熟悉,清楚的知道在特定环境下是如何运行的,然后仔细排查。例如,你想知道程序中的某个activity退出的时候,它之前所占用的内存是否有完整的释放干净了?首先你需要在activity处于前台的时候使用Heap Tool获取一份当前状态的内存快照,然后你需要创建一个几乎不这么占用内存的空白activity用来给前一个Activity进行跳转,其次在跳转到这个空白的activity的时候主动调用System.gc()方法来确保触发一个GC操作。最后,如果前面这个activity的内存都有全部正确释放,那么在空白activity被启动之后的内存快照中应该不会有前面那个activity中的任何对象了。

    如果你发现在空白activity的内存快照中有一些可疑的没有被释放的对象存在,那么接下去就应该使用Alocation Track Tool来仔细查找具体的可疑对象。我们可以从空白activity开始监听,启动到观察activity,然后再回到空白activity结束监听。这样操作以后,我们可以仔细观察那些对象,找出内存泄漏的真凶。

    11)Memory Performance

    通常来说,Android对GC做了大量的优化操作,虽然执行GC操作的时候会暂停其他任务,可是大多数情况下,GC操作还是相对很安静并且高效的。但是如果我们对内存的使用不恰当,导致GC频繁执行,这样就会引起不小的性能问题。

    为了寻找内存的性能问题,Android Studio提供了工具来帮助开发者。

    • Memory Monitor:查看整个app所占用的内存,以及发生GC的时刻,短时间内发生大量的GC操作是一个危险的信号。
    • Allocation Tracker:使用此工具来追踪内存的分配,前面有提到过。
    • Heap Tool:查看当前内存快照,便于对比分析哪些对象有可能是泄漏了的,请参考前面的Case。

    12)Tool - Memory Monitor

    Android Studio中的Memory Monitor可以很好的帮助我们查看程序的内存使用情况。

    13)Battery Performance

    电量其实是目前手持设备最宝贵的资源之一,大多数设备都需要不断的充电来维持继续使用。不幸的是,对于开发者来说,电量优化是他们最后才会考虑的的事情。但是可以确定的是,千万不能让你的应用成为消耗电量的大户。

    Purdue University研究了最受欢迎的一些应用的电量消耗,平均只有30%左右的电量是被程序最核心的方法例如绘制图片,摆放布局等等所使用掉的,剩下的70%左右的电量是被上报数据,检查位置信息,定时检索后台广告信息所使用掉的。如何平衡这两者的电量消耗,就显得非常重要了。

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

    • 我们应该尽量减少唤醒屏幕的次数与持续的时间,使用WakeLock来处理唤醒的问题,能够正确执行唤醒操作并根据设定及时关闭操作进入睡眠状态。
    • 某些非必须马上执行的操作,例如上传歌曲,图片处理等,可以等到设备处于充电状态或者电量充足的时候才进行。
    • 触发网络请求的操作,每次都会保持无线信号持续一段时间,我们可以把零散的网络请求打包进行一次操作,避免过多的无线信号引起的电量消耗。关于网络请求引起无线信号的电量消耗,还可以参考这里http://hukai.me/android-training-course-in-chinese/connectivity/efficient-downloads/efficient-network-access.html

    我们可以通过手机设置选项找到对应App的电量消耗统计数据。我们还可以通过Battery Historian Tool来查看详细的电量消耗。

    如果发现我们的App有电量消耗过多的问题,我们可以使用JobScheduler API来对一些任务进行定时处理,例如我们可以把那些任务重的操作等到手机处于充电状态,或者是连接到WiFi的时候来处理。关于JobScheduler的更多知识可以参考http://hukai.me/android-training-course-in-chinese/background-jobs/scheduling/index.html

    14)Understanding Battery Drain on Android

    电量消耗的计算与统计是一件麻烦而且矛盾的事情,记录电量消耗本身也是一个费电量的事情。唯一可行的方案是使用第三方监测电量的设备,这样才能够获取到真实的电量消耗。

    当设备处于待机状态时消耗的电量是极少的,以N5为例,打开飞行模式,可以待机接近1个月。可是点亮屏幕,硬件各个模块就需要开始工作,这会需要消耗很多电量。

    使用WakeLock或者JobScheduler唤醒设备处理定时的任务之后,一定要及时让设备回到初始状态。每次唤醒无线信号进行数据传递,都会消耗很多电量,它比WiFi等操作更加的耗电,详情请关注http://hukai.me/android-training-course-in-chinese/connectivity/efficient-downloads/efficient-network-access.html

    修复电量的消耗是另外一个很大的课题,这里就不展开继续了。

    15)Battery Drain and WakeLocks

    高效的保留更多的电量与不断促使用户使用你的App会消耗电量,这是矛盾的选择题。不过我们可以使用一些更好的办法来平衡两者。

    假设你的手机里面装了大量的社交类应用,即使手机处于待机状态,也会经常被这些应用唤醒用来检查同步新的数据信息。Android会不断关闭各种硬件来延长手机的待机时间,首先屏幕会逐渐变暗直至关闭,然后CPU进入睡眠,这一切操作都是为了节约宝贵的电量资源。但是即使在这种睡眠状态下,大多数应用还是会尝试进行工作,他们将不断的唤醒手机。一个最简单的唤醒手机的方法是使用PowerManager.WakeLock的API来保持CPU工作并防止屏幕变暗关闭。这使得手机可以被唤醒,执行工作,然后回到睡眠状态。知道如何获取WakeLock是简单的,可是及时释放WakeLock也是非常重要的,不恰当的使用WakeLock会导致严重错误。例如网络请求的数据返回时间不确定,导致本来只需要10s的事情一直等待了1个小时,这样会使得电量白白浪费了。这也是为何使用带超时参数的wakelock.acquice()方法是很关键的。但是仅仅设置超时并不足够解决问题,例如设置多长的超时比较合适?什么时候进行重试等等?

    解决上面的问题,正确的方式可能是使用非精准定时器。通常情况下,我们会设定一个时间进行某个操作,但是动态修改这个时间也许会更好。例如,如果有另外一个程序需要比你设定的时间晚5分钟唤醒,最好能够等到那个时候,两个任务捆绑一起同时进行,这就是非精确定时器的核心工作原理。我们可以定制计划的任务,可是系统如果检测到一个更好的时间,它可以推迟你的任务,以节省电量消耗。

    这正是JobScheduler API所做的事情。它会根据当前的情况与任务,组合出理想的唤醒时间,例如等到正在充电或者连接到WiFi的时候,或者集中任务一起执行。我们可以通过这个API实现很多免费的调度算法。

    从Android 5.0开始发布了Battery History Tool,它可以查看程序被唤醒的频率,又谁唤醒的,持续了多长的时间,这些信息都可以获取到。

    请关注程序的电量消耗,用户可以通过手机的设置选项观察到那些耗电量大户,并可能决定卸载他们。所以尽量减少程序的电量消耗是非常有必要的。


    知识共享许可协议:本站作品由HuKai创作,采用知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
    如果你觉得这篇文章对你有帮助,请点击下面的分享链接,你还可以选择扫描二维码进行打赏,承诺所有打赏都会用于公益!


    展开全文
  • 什么是拓扑结构_拓扑结构

    万次阅读 多人点赞 2018-09-09 09:17:01
    什么是拓扑结构?  首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、形状无关的“点”,而把连接实体的线路抽象成“线”,进而以图的形式来表示这些点与线之间关系的方法,其目的在于研究...

    什么是拓扑结构?
      首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、形状无关的“点”,而把连接实体的线路抽象成“线”,进而以图的形式来表示这些点与线之间关系的方法,其目的在于研究这些点、线之间的相连关系。表示点和线之间关系的图被称为拓扑结构图。拓扑结构与几何结构属于两个不同的数学概念。在几何结构中,
      我们要考察的是点、线之间的位置关系,或者说几何结构强调的是点与线所构成的形状及大小。如梯形、正方形、平行四边形及圆都属于不同的几何结构,但从拓扑结构的角度去看,由于点、线间的连接关系相同,从而具有相同的拓扑结构即环型结构。也就是说,不同的几何结构可能具有相同的拓扑结构。
      类似地,在计算机网络中,我们把计算机、终端、通信处理机等设备抽象成点,把连接这些设备的通信线路抽象成线,并将由这些点和线所构成的拓扑称为网络拓扑结构。
      网络拓扑结构反映出网络的结构关系,它对于网络的性能、可靠性以及建设管理成本等都有着重要的影响,因此网络拓扑结构的设计在整个网络设计中占有十分重要的地位,在网络构建时,网络拓常见的网络拓扑结构
      在计算机网络中常见的拓扑结构有总线型、星型、环型、树型和网状型等。
      1.总线型拓扑
    这里写图片描述
      如图1.4所示,总线型拓扑中采用单根传输线路作为传输介质,所有站点通过专门的连接器连到这个公共信道上,这个公共的信道称为总线。任何一个站点发送的数据都能通过总线传播,同时能被总线上的所有其他站点接收到。可见,总线型结构的网络是一种广播网络。扑结构往往是首先要考虑的因素之一。
      在总线结构中,总线有一定的负载能力,因此,总线长度有一定限制,一条总线也只能连接一定数量的结点。
      总线布局的特点是:结构简单灵活,非常便于扩充;可靠性高,网络响应速度快;设备量少、价格低、安装使用方便;共享资源能力强,极便于广播式工作即一个结点发送所有结点都可接收。总线型拓扑是基本局域网拓扑形式之一。
      在总线两端连接的器件称为端结器(末端阻抗匹配器、或终止器)。主要与总线进行阻抗匹配,最大限度吸收传送端部的能量,避免信号反射回总线产生不必要的干扰。
      总线形网络结构是目前使用最广泛的结构,也是最传统的一种主流网络结构,适合于信息管理系统、办公自动化系统领域的应用。
      2.星型拓扑
    这里写图片描述
      如图1.5所示,星型拓扑中有一个中心节点,其他各节点通过各自的线路与中心节点相连,形成辐射型结构。各节点间的通信必须通过中心节点的作用,如图A 到B 或A到C 都要经过中心节点D。
      星型拓扑的网络具有结构简单、易于建网和易于管理等特点。但这种结构要耗费大量的电缆,同时中心节点的故障会直接造成整个网络的瘫痪。星型拓扑也经常应用于局域网中。
      星型布局是以中央结点为中心与各结点连接而组成的,各结点与中央结点通过点与点方式连接,中央点执行集中式通信控制策略,因此中央结点相当复杂,负担也重。
      目前流行的PBX就是星型拓扑结构的典型实例,如图1.5(右)所示。
      以星型拓扑结构组网,其中任何两个站点要进行通信都必须经过中央结点控制。中
      央结点主要功能有
      1) 为需要通信的设备建立物理连接
      2) 为两台设备通信过程中维持这一通路
      3) 在完成通信或不成功时,拆除通道
      在文件服务器/工作站(File Server/Workstation )局域网模式中,中心点为文件服务器,存放共享资源。由于这种拓扑结构,中心点与多台工作站相连,为便于集中连线,目前多采用集线器(HUB)。
      星型拓扑结构特点:网络结构简单,便于管理、集中控制, 组网容易;网络延迟时间短,误码率低,网络共享能力较差,通信线路利用率不高,中央节点负担过重,可同时连双绞线、同轴电缆及光纤等多种媒介。
      树型拓扑结构可以看作成星型拓扑的一种扩展,也称扩展星型拓扑。
      3.环型拓扑
    这里写图片描述
      如图1.6 所示,在环型拓扑中,各节点和通信线路连接形成的一个闭合的环。在环路中,数据按照一个方向传输。发送端发出的数据,延环绕行一周后,回到发送端,由发送端将其从环上删除。我们可以看到任何一个节点发出的数据都可以被环上的其他节点接收到。
      环型拓扑具有结构简单,容易实现,传输时延确定以及路径选择简单等优点,但是,网络中的每一个节点或连接节点的通信线路都有可能成为网络可靠性的瓶颈。当网络中的任何一个节点出现故障都可能会造成网络的瘫痪。另外,在这种拓扑结构中,节点的加入和拆除过程比较复杂。环型拓扑也是局域网中常用的一种拓扑形式。
      环形网的特点是:信息在网络中沿固定方向流动,两个结点间仅有唯一的通路,大大简化了路径选择的控制;某个结点发生故障时,可以自动旁路,可靠性较高;由于信息是串行穿过多个结点环路接口,当结点过多时,影响传输效率,使网络响应时间变长。但当网络确定时,其延时固定,实时性强;由于环路封闭故扩充不方便。
      环形网也是微机局域网常用拓扑结构之一,适合信息处理系统和工厂自动化系统。1985年IBM公司推出的令牌环形网(IBM Token Ring)是其典范。在FDDI得以应用推广后,这种结构会进一步得到采用。
      4.网状拓扑
    这里写图片描述
      在网状拓扑结构中,节点之间的连接是任意的,每个节点都有多条线路与其他节点相连,这样使得节点之间存在多条路径可选,如图1.7中从A 到C 可以是A-B-C 也可以是A-D-B-C,在传输数据时可以灵活的选用空闲路径或者避开故障线路。
      可见网状拓扑可以充分、合理的使用网络资源,并且具有可靠性高的优点。我们知道,广域网覆盖面积大,传输距离长,网络的故障会给大量的用户带来严重的危害,因此在广域网中,为了提高网络的可靠性通常采用网状拓扑结构,如图1.7(右)所示为一个简单的广域网示意图。
      但是我们也应该看到,这个优点是以高投资和高复杂的管理为代价的。将多个子网或多个局域网连接起来构成网状型拓扑结构。在一个子网中,集线器、中继器将多个设备连接起来,而桥接器、路由器及网关则将子网连接起来。根据组网硬件不同,主要有三种网状型拓扑:
      网状网:在一个大的区域内,用无线通信连路连接一个大型网络时,网状网是最好的拓扑结构。通过路由器与路由器相连,可让网络选择一条最快的路径传送数据。
      主干网:通过桥接器与路由器把不同的子网或LAN 连接起来形成单个总线或环型拓扑结构,这种网通常采用光纤做主干线。
      星状相连网:利用一些叫做超级集线器的设备将网络连接起来,由于星型结构的特点,网络中任一处的故障都可容易查找并修复。应该指出,在实际组网中,拓扑结构不一定是单一的,通常是几种结构的混用。
    这里写图片描述
      比如,将总线型与星型结合起来就形成了总线型/星型拓扑结构,用一条或多条总线把多组设备连接起来,相连的每组设备呈星型分布。采用这种拓扑结构,用户很容易配置和重新配置网络设备。如图1.8 所示。

    展开全文
  • Android性能优化典范(四)

    千次阅读 2016-01-12 17:46:25
    作者简介:胡凯(@胡凯me),腾讯Android工程师,热爱开源与分享,维护Android官方培训课程协作项目,关注Android应用性能优化的...Android性能优化典范第4季的课程学习笔记终于在2015年的最后一天完成了(并于2016...

    作者简介:胡凯(@胡凯me),腾讯Android工程师,热爱开源与分享,维护Android官方培训课程协作项目,关注Android应用性能优化的总结与分享,推崇Android官方最佳实践。个人博客:http://hukai.me,Github:https://github.com/kesenhoo

    图片描述

    Android性能优化典范第4季的课程学习笔记终于在2015年的最后一天完成了(并于2016年1月12日正式发布在CSDN上),文章共17个段落,包含的内容大致有:优化网络请求的行为,优化安装包的资源文件,优化数据传输的效率,性能优化的几大基础原理等等。因为学习认知水平有限,肯定存在不少理解偏差甚至错误的地方,请多多交流指正!

    系列阅读

    • Android 性能优化典范(一):主要从 Android 的渲染机制、内存与 GC、电量优化三个方面展开,介绍了 Android 中性能问题的底层工作原理,以及如何通过工具来找出性能问题及提升性能的建议。

    • Android 性能优化典范(二):20 个短视频,主要内容为:电量优化、网络优化、Android Wear 上如何做优化、使用对象池来提高效率、LRU Cache、Bitmap 的缩放、缓存、重用、PNG 压缩、自定义 View 的性能、提升设置 alpha 之后 View 的渲染性能,以及 Lint、StictMode 等工具的使用技巧。

    • Android 性能优化典范(三):更高效的 ArrayMap 容器,使用 Android 系统提供的特殊容器来避免自动装箱,避免使用枚举类型,注意onLowMemoryonTrimMemory的回调,避免内存泄漏,高效的位置更新操作,重复 layout 操作的性能影响,以及使用 Batching,Prefetching 优化网络请求,压缩传输数据等使用技巧。

    • Android 性能优化典范(四):优化网络请求的行为,优化安装包的资源文件,优化数据传输的效率,性能优化的几大基础原理等。

    • Android 性能优化典范(五):文章共有10个段落,涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask、HandlerThread、IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项。这是一篇了解 Android 多线程编程不可多得的基础文章,清楚地了解这些 Android 系统提供的多线程基础组件之间的差异以及优缺点,才能够在项目实战中做出最恰当的选择。

    • Android 性能优化典范(六):文章共 6 个段落,涉及的内容主要有程序启动时间性能优化的三个方面:优化 activity 的创建过程,优化 Application 对象的启动过程,正确使用启动显屏达到优化程序启动性能的目的。另外还介绍了减少安装包大小的 checklist 以及如何使用 VectorDrawable 来减少安装包的大小。


    1) Cachematters for networking

    想要使得Android系统上的网络访问操作更加的高效就必须做好网络数据的缓存,这是提高网络访问性能最基础的步骤之一。从手机的缓存中直接读取数据肯定比从网络上获取数据要更加的便捷高效,特别是对于那些会被频繁访问到的数据,需要把这些数据缓存到设备上,以便更加快速的进行访问。

    Android系统上关于网络请求的Http Response Cache是默认关闭的,这样会导致每次即使请求的数据内容是一样的也会需要重复被调用执行,效率低下。我们可以通过下面的代码示例开启HttpResponseCache

    图片描述

    开启Http Response Cache之后,Http操作相关的返回数据就会缓存到文件系统上,不仅仅是主程序自己编写的网络请求相关的数据会被缓存,另外引入的library库中的网络相关的请求数据也会被缓存到这个Cache中。

    网络请求的场景有可以是普通的http请求,也可以打开某个URL去获取数据,如下图所示:

    图片描述

    我们有两种方式来清除HttpResponseCache的缓存数据:第一种方式是缓存溢出的时候删除最旧最老的文件,第二种方式是通过Http返回Header中的Cache-Control字段来进行控制的。如下图所示:

    图片描述

    通常来说,HttpResponseCache会缓存所有的返回信息,包括实际的数据与Header的部分.一般情况下,这个Cache会自动根据协议返回Cache-Control的内容与当前缓存的数据量来决定哪些数据应该继续保留,哪些数据应该删除。但是在一些极端的情况下,例如服务器返回的数据没有设置Cache废弃的时间,或者是本地的Cache文件系统与返回的缓存数据有冲突,或者是某些特殊的网络环境导致HttpResponseCache工作异常,在这些情况下就需要我们自己来实现Http的缓存Cache。

    实现自定义的http缓存,需要解决两个问题:第一个是实现一个DiskCacheManager,另外一个是制定Cache的缓存策略。关于DiskCacheManager,我们可以扩展Android系统提供的DiskLruCache来实现。而Cache的缓存策略,相对来说复杂一些,我们可能需要把部分JSON数据设计成不能缓存的,另外一些JSON数据设计成可以缓存几天的,把缩略图设计成缓存一两天的等等,为不同的数据类型根据他们的使用特点制定不同的缓存策略。

    图片描述

    想要比较好的实现这两件事情,如果全部自己从头开始写会比较繁琐复杂,所幸的是,有不少著名的开源框架帮助我们快速的解决了那些问题。我们可以使用VollyokHTTPPicasso来实现网络缓存。

    实现好网络缓存之后,我们可以使用Android Studio里面的Network Traffic Tools来查看网络数据的请求与返回情况,另外我们还可以使用AT&T ARO工具来抓取网络数据包进行分析查看。

    2) Optimizing Network Request Frequencies

    应用程序的一个基础功能是能够保持确保界面上呈现的信息是即时最新的,例如呈现最新的新闻,天气,信息流等等信息。但是,过于频繁的促使手机客户端应用去同步最新的服务器数据会对性能产生很大的负面影响,不仅仅使得CPU不停的在工作,内存,网络流量,电量等等都会持续的被消耗,所以在进行网络请求操作的时候一定要避免多度同步操作。

    退到后台的应用为了能够在切换回前台的时候呈现最新的数据,会偷偷在后台不停的做同步的操作。这种行为会带来很严重的问题,首先因为网络请求的行为异常的耗电,其次不停的进行网络同步会耗费很多带宽流量。

    为了能够尽量的减少不必要的同步操作,我们需要遵守下面的一些规则:

    • 首先我们要对网络行为进行分类,区分需要立即更新数据的行为和其他可以进行延迟的更新行为,为不同的场景进行差异化处理。
    • 其次要避免客户端对服务器的轮询操作,这样会浪费很多的电量与带宽流量。解决这个问题,我们可以使用Google Cloud Message来对更新的数据进行推送。
    • 然后在某些必须做同步的场景下,需要避免使用固定的间隔频率来进行更新操作,我们应该在返回的数据无更新的时候,使用双倍的间隔时间来进行下一次同步。
    • 最后更进一步,我们还可以通过判断当前设备的状态来决定同步的频率,例如判断设备处于休眠,运动等不同的状态设计各自不同时间间隔的同步频率。

    图片描述

    另外,我们还可以通过判断设备是否连接上Wi-Fi,是否正在充电来决定更新的频率。为了能够方便的实现这个功能,Android为我们提供了GCMNetworkManager来判断设备当下的状态,从而设计更加高效的网络同步操作,如下图所示:

    图片描述

    3) Effective Prefetching

    关于提升网络操作的性能,除了避免频繁的网络同步操作之外,还可以使用捆绑批量访问的方式来减少访问的频率,为了达到这个目的,我们就需要了解Prefetching。

    举个例子,在某个场景下,一开始发出了网络请求得到了某张图片,隔了10s之后,发出第二次请求想要拿到另外一张图片,再隔了6s发出第三张图片的网络请求。这会导致设备的无线蜂窝一直处于高消耗的状态。Prefetching就是预先判定那些可能马上就会使用到的网络资源,捆绑一起集中进行网络请求。这样能够极大的减少电量的消耗,提升设备的续航时间。

    图片描述

    使用Prefetching的难点在于如何判断事先获取的数据量到底是多少,如果预取的数据量偏少,那么就起不到什么效果,但是如果预取过多,又可能导致访问的时间过长。

    图片描述

    那么问题来了,到底预取多少才比较合适呢?一个比较普适的规则是,在3G网络下可以预取1-5MB的数据量,或者是按照提前预期后续1-2分钟的数据作为基线标准。在实际的操作当中,我们还需要考虑当前的网络速度来决定预取的数据量,例如在同样的时间下,4G网络可以获取到12张图片的数据,而2G网络则只能拿到3张图片的数据。所以,我们还需要把当前的网络环境情况添加到设计预取数据量的策略当中去。判断当前设备的状态与网络情况,可以使用前面提到过的GCMNetworkManager

    4) Adapting to Latency

    网络延迟通常来说很容易被用户察觉到,严重的网络延迟会对用户体验造成很大的影响,用户很容易抱怨应用程序写的不好。

    一个典型的网络操作行为,通常包含以下几个步骤:首先手机端发起网络请求,到达网络服务运营商的基站,再转移到服务提供者的服务器上,经过解码之后,接着访问本地的存储数据库,获取到数据之后,进行编码,最后按照原来传递的路径逐层返回。如下图所示:

    图片描述

    在上面的网络请求链路当中的任何一个环节都有可能导致严重的延迟,成为性能瓶颈,但是这些环节可能出现的问题,客户端应用是无法进行调节控制的,应用能够做的就只是根据当前的网络环境选择当下最佳的策略来降低出现网络延迟的概率。主要的实施步骤有两步:第1步检测收集当前的网络环境信息,第2步根据当前收集到的信息进行网络请求行为的调整。

    关于第1步检测当前的网络环境,我们可以使用系统提供的API来获取到相关的信息,如下图所示:

    图片描述

    通过上面的示例,我们可以获取到移动网络的详细子类型,例如4G(LTE)、3G等等,详细分类见下图,获取到详细的移动网络类型之后,我们可以根据当前网络的速率来调整网络请求的行为:

    图片描述

    关于第2步根据收集到的信息进行策略的调整,通常来说,我们可以把网络请求延迟划分为三档:例如把网络延迟小于60ms的划分为GOOD,大于220ms的划分为BAD,介于两者之间的划分为OK(这里的60ms、220ms会需要根据不同的场景提前进行预算推测)。如果网络延迟属于GOOD的范畴,我们就可以做更多比较激进的预取数据的操作,如果网络延迟属于BAD的范畴,我们就应该考虑把当下的网络请求操作Hold住等待网络状况恢复到GOOD的状态再进行处理。

    图片描述

    前面提到说60ms、220ms是需要提前自己预测的,可是预测的工作相当复杂。首先针对不同的机器与网络环境,网络延迟的三档阈值都不太一样,出现的概率也不尽相同,我们会需要针对这些不同的用户与设备选择不同的阈值进行差异化处理:

    图片描述

    Android官方为了帮助我们设计自己的网络请求策略,提供了模拟器的网络流量控制功能来对实际环境进行模拟测量,或者还可以使用AT&T提供的AT&T Network Attenuator来帮助预估网络延迟。

    5) Minimizing Asset Payload

    为了能够减小网络传输的数据量,我们需要对传输的数据做压缩的处理,这样能够提高网络操作的性能。首先不同的网络环境,下载速度以及网络延迟是存在差异的,如下图所示:

    图片描述

    如果我们选择在网速更低的网络环境下进行数据传输,这就意味着需要执行更长的时间,而更长的网络操作行为,会导致电量消耗更加严重。另外传输的数据如果不做压缩处理,也同样会增加网络传输的时间,消耗更多的电量。不仅如此,未经过压缩的数据,也会消耗更多的流量,使得用户需要付出更多的流量费。

    通常来说,网络传输数据量的大小主要由两部分组成:图片与序列化的数据,那么我们需要做的就是减少这两部分的数据传输大小,分下面两个方面来讨论。

    • A)首先需要做的是减少图片的大小,选择合适的图片保存格式是第一步。下图展示了PNG,JPEG,WEBP三种主流格式在占用空间与图片质量之间的对比:

    图片描述

    对于JPEG与WEBP格式的图片,不同的清晰度对占用空间的大小也会产生很大的影响,适当的减少JPG Quality,可以大大地缩小图片占用的空间大小。

    另外,我们需要为不同的使用场景提供当前场景下最合适的图片大小,例如针对全屏显示的情况我们会需要一张清晰度比较高的图片,而如果只是显示为缩略图的形式,就只需要服务器提供一个相对清晰度低很多的图片即可。服务器应该支持到为不同的使用场景分别准备多套清晰度不一样的图片,以便在对应的场景下能够获取到最适合自己的图片。这虽然会增加服务端的工作量,可是这个付出却十分值得!

    • B)其次需要做的是减少序列化数据的大小。JSON与XML为了提高可读性,在文件中加入了大量的符号,空格等等字符,而这些字符对于程序来说是没有任何意义的。我们应该使用Protocal Buffers,Nano-Proto-Buffers,FlatBuffer来减小序列化的数据的大小。

    Android系统为我们提供了工具来查看网络传输的数据情况,打开Android Studio的Monitor,里面有网络访问的模块。或者是打开AT&T提供的ARO工具来查看网络请求状态。

    6) Service Performance Patterns

    Service是Android程序里面最常用的基础组件之一,但是使用Service很容易引起电量的过度消耗以及系统资源的未及时释放。学会在何时启用Service以及使用何种方式杀掉Service就显得十分有必要了。

    简要过一下Service的特性:Service和UI没有关联,Service的创建,执行,销毁Service都是需要占用系统时间和内存的。另外Service是默认运行在UI线程的,这意味着Service可能会影响到系统的流畅度。

    使用Service应该遵循下面的一些规则:

    • 避免错误的使用Service,例如我们不应该使用Service来监听某些事件的变化,不应该搞一个Service在后台对服务器不断的进行轮询(应该使用Google Cloud Messaging)
    • 如果已经事先知道Service里面的任务应该执行在后台线程(非默认的主线程)的时候,我们应该使用IntentService或者结合HanderThread,AsycnTask Loader实现的Service。

    Android系统为我们提供了以下的一些异步相关的工具类

    • GCM
    • BroadcastReciever
    • LocalBroadcastReciever
    • WakefulBroadcastReciver
    • HandlerThreads
    • AsyncTaskLoaders
    • IntentService

    如果使用上面的诸多方案还是无法替代普通的Service,那么需要注意的就是如何正确的关闭Service。

    • 普通的Started Service,需要通过stopSelf()来停止Service;

    图片描述

    • 另外一种Bound Service,会在其他组件都unBind之后自动关闭自己。

    图片描述

    把上面两种Service进行合并之后,我们可以得到如下图所示的Service(相关知识,还可以参考http://hukai.me/android-notes-services/, http://hukai.me/android-notes-bound-services/

    图片描述

    7) Removing unused code

    使用第三方库(library)可以在不用自己编写大量代码的前提下帮助我们解决一些难题,节约大量的时间,但是这些引入的第三方库很可能会导致主程序代码臃肿冗余。

    如果我们处在人力、财力都相对匮乏的情况下,通常会倾向大量使用第三方库来帮助编写应用程序。这其实是无可厚非的,那些著名的第三方库的可行性早就被很多应用所采用并实践证明过。但是这里面存在的问题是,如果我们因为只需要某个library的一小部分功能而把整个library都导入自己的项目,这就会引起代码臃肿。一旦发生代码臃肿,用户就会下载到安装包偏大的应用程序,另外因为代码臃肿,还很有可能会超过单个编译文件只能有65536个方法的上限。解决这个问题的办法是使用MultiDex的方案,可是这实在是无奈之举,原则上,我们还是应该尽量避免出现这种情况。

    Android为我们提供了Proguard的工具来帮助应用程序对代码进行瘦身,优化,混淆的处理。它会帮助移除那些没有使用到的代码,还可以对类名,方法名进行混淆处理以避免程序被反编译。举个例子,Google I/O 2015这个应用使用了大量的library,没有经过Proguard处理之前编译出来的包是8.4Mb大小,经过处理之后的包仅仅是4.1Mb大小。

    使用Proguard相当的简单,只需要在build.gradle文件中配置minifEnable为true即可,如下图所示:

    图片描述

    但是Proguard还是不足够聪明到能够判断哪些类,哪些方法是不能够被混淆的,针对这些情况,我们需要手动的把这些需要保留的类名与方法名添加到Proguard的配置文件中,如下图所示:

    图片描述

    在使用library的时候,需要特别注意这些library在proguard配置上的说明文档,我们需要把这些配置信息添加到自己的主项目中。关于Proguard的详细说明,请看官方文档http://developer.android.com/tools/help/proguard.html

    8) Removing unused resources

    减少APK安装包的大小也是Android程序优化中很重要的一个方面,我们不应该给用户下载到一个臃肿的安装包。假设这样一个场景,我们引入了Google Play Service的library,是想要使用里面的Maps的功能,但是里面的登入等等其他功能是不需要的,可是这些功能相关的代码与图片资源,布局资源如果也被引入我们的项目,这样就会导致我们的程序安装包臃肿。

    所幸的是,我们可以使用Gradle来帮助我们分析代码,分析引用的资源,对于那些没有被引用到的资源,会在编译阶段被排除在APK安装包之外,要实现这个功能,对我们来说仅仅只需要在build.gradle文件中配置shrinkResource为true就好了,如下图所示:

    图片描述

    为了辅助gradle对资源进行瘦身,或者是某些时候的特殊需要,我们可以通过tools:keep或者是tools:discard标签来实现对特定资源的保留与废弃,如下图所示:

    图片描述

    Gradle目前无法对values,drawable等根据运行时来决定使用的资源进行优化,对于这些资源,需要我们自己来确保资源不会有冗余。

    9) Perf Theory: Caching

    当我们讨论性能优化的时候,缓存是最常见最有效的策略之一。无论是为了提高CPU的计算速度还是提高数据的访问速度,在绝大多数的场景下,我们都会使用到缓存。关于缓存是如何提高效率的,这里就不赘述了。

    那么在什么地方,在何时应该利用好缓存来提高效率呢?请看下面的例子,很明显的演示了在某些细节上是如何利用缓存的原理来提高代码的执行效率的:

    图片描述

    图片描述

    类似上面的例子采用缓存原理的地方还有很多,例如缓存到内存里面的图片资源,网络请求返回数据的缓存等等。总之,使用缓存就是为了减少不必要的操作,尽量复用已有的对象来提高效率。

    10) Perf Theory: Approximation(近似法)

    很多时候,我们都需要学会在性能更优与体验更好之间做一定的权衡取舍。为了获取更好的表现性能,我们可能会需要牺牲一些用户体验,例如把某些细节做删除或者是降级处理以便有更好的性能。例如,导航类的应用,如果在导航期间是不停的执行定位的操作,这样能够很及时的获取到最新的位置信息以及当下位置相关的其他提示信息,但是这样会导致网络流量以及手机电量的过度消耗。所以我们可以做一定的降级处理,每隔固定的一段时间才去获取一次位置信息,损失一点及时性来换取更长的续航时间。

    还有很多地方都会用到近似法则来优化程序的性能,例如使用一张比较接近实际大小的图片来替代原图,换取更快的加载速度。所以对于那些对计算结果要求不需要十分精确的场景,我们可以使用近似法则来提高程序的性能。

    11) Perf Theory: Culling(遴选,挑选)

    在以前的性能优化课程里面,我们知道可以通过减少Overdraw来提高程序的渲染性能(主要手段有移除非必须的background,减少重叠的布局,使用clipRect来提高自定义View的绘制性能),今天在这里要介绍的另外一个提高性能的方法是逐步对数据进行过滤筛选,减小搜索的数据集,以此提高程序的执行性能。例如我们需要搜索到居住在某个地方,年龄是多少,符合某些特定条件的候选人,就可以通过逐层过滤筛选的方式来提高后续搜索的执行效率。

    12) Perf Theory: Threading

    使用多线程并发处理任务,从某种程度上可以快速提高程序的执行性能。对于Android程序来说,主线程通常也成为UI线程,需要处理UI的渲染,响应用户的操作等等。对于那些可能影响到UI线程的任务都需要特别留意是否有必要放到其他的线程来进行处理。如果处理不当,很有可能引起程序ANR。关于多线程的使用建议,可以参考官方的培训课程http://developer.android.com/training/best-background.html

    13) Perf Theory: Batching

    关于Batching,在前几季的性能优化课程里面也不止一次提到,下面使用一张图演示下Batching的原理:

    图片描述

    网络请求的批量执行是另外一个比较适合说明batching使用场景的例子,因为每次发起网络请求都相对来说比较耗时耗电,如果能够做到批量一起执行,可以大大的减少电量的消耗。

    图片描述

    14) Serialization performance

    数据的序列化是程序代码里面必不可少的组成部分,当我们讨论到数据序列化的性能的时候,需要了解有哪些候选的方案,他们各自的优缺点是什么。首先什么是序列化?用下面的图来解释一下:

    图片描述

    数据序列化的行为可能发生在数据传递过程中的任何阶段,例如网络传输,不同进程间数据传递,不同类之间的参数传递,把数据存储到磁盘上等等。通常情况下,我们会把那些需要序列化的类实现Serializable接口(如下图所示),但是这种传统的做法效率不高,实施的过程会消耗更多的内存。

    图片描述

    但是我们如果使用GSON库来处理这个序列化的问题,不仅仅执行速度更快,内存的使用效率也更高。Android的XML布局文件会在编译的阶段被转换成更加复杂的格式,具备更加高效的执行性能与更高的内存使用效率。

    图片描述

    下面介绍三个数据序列化的候选方案:

    • Protocal Buffers:强大,灵活,但是对内存的消耗会比较大,并不是移动终端上的最佳选择。
    • Nano-Proto-Buffers:基于Protocal,为移动终端做了特殊的优化,代码执行效率更高,内存使用效率更佳。
    • FlatBuffers:这个开源库最开始是由Google研发的,专注于提供更优秀的性能。

    上面这些方案在性能方面的数据对比如下图所示:

    图片描述

    图片描述

    为了避免序列化带来的性能问题,我们其实可以考虑使用SharedPreference或者SQLite来存储那些数据,避免需要先把那些复杂的数据进行序列化的操作。

    15) Smaller Serialized Data

    数据呈现的顺序以及结构会对序列化之后的空间产生不小的影响。通常来说,一般的数据序列化的过程如下图所示:

    图片描述

    上面的过程,存在两个弊端,第一个是重复的属性名称:

    图片描述

    另外一个是GZIP没有办法对上面的数据进行更加有效的压缩,假如相似数据间隔了32k的数据量,这样GZIP就无法进行更加有效的压缩:

    图片描述

    但是我们稍微改变下数据的记录方式,就可以得到占用空间更小的数据,如下图所示:

    图片描述

    通过优化,至少有三方面的性能提升,如下图所示:

    1)减少了重复的属性名:

    图片描述

    2)使得GZIP的压缩效率更高:

    图片描述

    3)同样的数据类型可以批量优化:

    图片描述

    16) Caching UI data

    如今绝大多数的应用界面上呈现的数据都依赖于网络请求返回的结果,如何做到在网络数据返回之前避免呈现一个空白的等待页面呢(当然这里说的是非首次冷启动的情况)?这就会涉及到如何缓存UI界面上的数据。

    缓存UI界面上的数据,可以采用方案有存储到文件系统,Preference,SQLite等等,做了缓存之后,这样就可以在请求数据返回结果之前,呈现给用户旧的数据,而不是使用正在加载的方式让用户什么数据都看不到,当然在请求网络最新数据的过程中,需要有正在刷新的提示。至于到底选择哪个方案来对数据进行缓存,就需要根据具体情况来做选择了。

    17) CPU Frequency Scaling

    调节CPU的频率会执行的性能产生较大的影响,为了最大化的延长设备的续航时间,系统会动态调整CPU的频率,频率越高执行代码的速度自然就越快。

    图片描述

    Android系统会在电量消耗与表现性能之间不断的做权衡,当有需要的时候会迅速调整CPU的频率到一个比较高负荷的状态,当程序不需要高性能的时候就会降低频率来确保更长的续航时间。

    图片描述

    Android系统检测到需要调整CPU的频率到CPU频率真的达到对应频率会需要花费大概20ms的时间,在此期间很有可能会因为CPU频率不够而导致代码执行偏慢。

    图片描述

    我们可以使用Systrace工具来导出CPU的执行情况,以便帮助定位性能问题。

    系列阅读:
    Android性能优化典范(一)
    Android性能优化典范(二)
    Android性能优化典范(三)

    责任编辑:唐小引(@唐门教主),邮箱:tangxy@csdn.net。

    本文为CSDN特约文章,未经允许不得转载,如需转载请联系mobile#csdn.net(#换成@)

    展开全文
  • 什么是拓扑结构?  首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、形状无关的“点”,而把连接实体的线路抽象成“线”,进而以图的形式来表示这些点与线之间关系的方法,其目的在于研究这些...

    什么是拓扑结构? 
      首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、形状无关的“点”,而把连接实体的线路抽象成“线”,进而以图的形式来表示这些点与线之间关系的方法,其目的在于研究这些点、线之间的相连关系。表示点和线之间关系的图被称为拓扑结构图。拓扑结构与几何结构属于两个不同的数学概念。在几何结构中, 
      我们要考察的是点、线之间的位置关系,或者说几何结构强调的是点与线所构成的形状及大小。如梯形、正方形、平行四边形及圆都属于不同的几何结构,但从拓扑结构的角度去看,由于点、线间的连接关系相同,从而具有相同的拓扑结构即环型结构。也就是说,不同的几何结构可能具有相同的拓扑结构。 
      类似地,在计算机网络中,我们把计算机、终端、通信处理机等设备抽象成点,把连接这些设备的通信线路抽象成线,并将由这些点和线所构成的拓扑称为网络拓扑结构。 
      网络拓扑结构反映出网络的结构关系,它对于网络的性能、可靠性以及建设管理成本等都有着重要的影响,因此网络拓扑结构的设计在整个网络设计中占有十分重要的地位,在网络构建时,网络拓常见的网络拓扑结构 
      在计算机网络中常见的拓扑结构有总线型、星型、环型、树型和网状型等。 
      1.总线型拓扑 
    这里写图片描述 
      如图1.4所示,总线型拓扑中采用单根传输线路作为传输介质,所有站点通过专门的连接器连到这个公共信道上,这个公共的信道称为总线。任何一个站点发送的数据都能通过总线传播,同时能被总线上的所有其他站点接收到。可见,总线型结构的网络是一种广播网络。扑结构往往是首先要考虑的因素之一。 
      在总线结构中,总线有一定的负载能力,因此,总线长度有一定限制,一条总线也只能连接一定数量的结点。 
      总线布局的特点是:结构简单灵活,非常便于扩充;可靠性高,网络响应速度快;设备量少、价格低、安装使用方便;共享资源能力强,极便于广播式工作即一个结点发送所有结点都可接收。总线型拓扑是基本局域网拓扑形式之一。 
      在总线两端连接的器件称为端结器(末端阻抗匹配器、或终止器)。主要与总线进行阻抗匹配,最大限度吸收传送端部的能量,避免信号反射回总线产生不必要的干扰。 
      总线形网络结构是目前使用最广泛的结构,也是最传统的一种主流网络结构,适合于信息管理系统、办公自动化系统领域的应用。 
      2.星型拓扑 
    这里写图片描述 
      如图1.5所示,星型拓扑中有一个中心节点,其他各节点通过各自的线路与中心节点相连,形成辐射型结构。各节点间的通信必须通过中心节点的作用,如图A 到B 或A到C 都要经过中心节点D。 
      星型拓扑的网络具有结构简单、易于建网和易于管理等特点。但这种结构要耗费大量的电缆,同时中心节点的故障会直接造成整个网络的瘫痪。星型拓扑也经常应用于局域网中。 
      星型布局是以中央结点为中心与各结点连接而组成的,各结点与中央结点通过点与点方式连接,中央点执行集中式通信控制策略,因此中央结点相当复杂,负担也重。 
      目前流行的PBX就是星型拓扑结构的典型实例,如图1.5(右)所示。 
      以星型拓扑结构组网,其中任何两个站点要进行通信都必须经过中央结点控制。中 
      央结点主要功能有 
      1) 为需要通信的设备建立物理连接 
      2) 为两台设备通信过程中维持这一通路 
      3) 在完成通信或不成功时,拆除通道 
      在文件服务器/工作站(File Server/Workstation )局域网模式中,中心点为文件服务器,存放共享资源。由于这种拓扑结构,中心点与多台工作站相连,为便于集中连线,目前多采用集线器(HUB)。 
      星型拓扑结构特点:网络结构简单,便于管理、集中控制, 组网容易;网络延迟时间短,误码率低,网络共享能力较差,通信线路利用率不高,中央节点负担过重,可同时连双绞线、同轴电缆及光纤等多种媒介。 
      树型拓扑结构可以看作成星型拓扑的一种扩展,也称扩展星型拓扑。 
      3.环型拓扑 
    这里写图片描述 
      如图1.6 所示,在环型拓扑中,各节点和通信线路连接形成的一个闭合的环。在环路中,数据按照一个方向传输。发送端发出的数据,延环绕行一周后,回到发送端,由发送端将其从环上删除。我们可以看到任何一个节点发出的数据都可以被环上的其他节点接收到。 
      环型拓扑具有结构简单,容易实现,传输时延确定以及路径选择简单等优点,但是,网络中的每一个节点或连接节点的通信线路都有可能成为网络可靠性的瓶颈。当网络中的任何一个节点出现故障都可能会造成网络的瘫痪。另外,在这种拓扑结构中,节点的加入和拆除过程比较复杂。环型拓扑也是局域网中常用的一种拓扑形式。 
      环形网的特点是:信息在网络中沿固定方向流动,两个结点间仅有唯一的通路,大大简化了路径选择的控制;某个结点发生故障时,可以自动旁路,可靠性较高;由于信息是串行穿过多个结点环路接口,当结点过多时,影响传输效率,使网络响应时间变长。但当网络确定时,其延时固定,实时性强;由于环路封闭故扩充不方便。 
      环形网也是微机局域网常用拓扑结构之一,适合信息处理系统和工厂自动化系统。1985年IBM公司推出的令牌环形网(IBM Token Ring)是其典范。在FDDI得以应用推广后,这种结构会进一步得到采用。 
      4.网状拓扑 
    这里写图片描述 
      在网状拓扑结构中,节点之间的连接是任意的,每个节点都有多条线路与其他节点相连,这样使得节点之间存在多条路径可选,如图1.7中从A 到C 可以是A-B-C 也可以是A-D-B-C,在传输数据时可以灵活的选用空闲路径或者避开故障线路。 
      可见网状拓扑可以充分、合理的使用网络资源,并且具有可靠性高的优点。我们知道,广域网覆盖面积大,传输距离长,网络的故障会给大量的用户带来严重的危害,因此在广域网中,为了提高网络的可靠性通常采用网状拓扑结构,如图1.7(右)所示为一个简单的广域网示意图。 
      但是我们也应该看到,这个优点是以高投资和高复杂的管理为代价的。将多个子网或多个局域网连接起来构成网状型拓扑结构。在一个子网中,集线器、中继器将多个设备连接起来,而桥接器、路由器及网关则将子网连接起来。根据组网硬件不同,主要有三种网状型拓扑: 
      网状网:在一个大的区域内,用无线通信连路连接一个大型网络时,网状网是最好的拓扑结构。通过路由器与路由器相连,可让网络选择一条最快的路径传送数据。 
      主干网:通过桥接器与路由器把不同的子网或LAN 连接起来形成单个总线或环型拓扑结构,这种网通常采用光纤做主干线。 
      星状相连网:利用一些叫做超级集线器的设备将网络连接起来,由于星型结构的特点,网络中任一处的故障都可容易查找并修复。应该指出,在实际组网中,拓扑结构不一定是单一的,通常是几种结构的混用。 
    这里写图片描述 
      比如,将总线型与星型结合起来就形成了总线型/星型拓扑结构,用一条或多条总线把多组设备连接起来,相连的每组设备呈星型分布。采用这种拓扑结构,用户很容易配置和重新配置网络设备。如图1.8 所示。

     

    展开全文
  • 拓扑结构

    千次阅读 2018-05-20 13:52:12
    转自:https://blog.csdn.net/starshinning975/article/details/53511343什么是拓扑结构? 首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、...表示点和线之间关系的图被称为拓扑结构图。拓扑...
  • 近年来,全国各地涌现出了多座运用BIM打造的地标结构建筑,小编挑选其中几个极具特色的代表的建筑为大家介绍。   北京凤凰传媒中心——在运维阶段进行FM调度与分析的强大信息模型 凤凰国际传媒中心项目...
  • 软件体系结构期末考试总结

    千次阅读 多人点赞 2019-12-30 23:19:35
    今天刚考完软件体系结构,把考前的知识点总结发到群里,仅供自己参考,但是里面的内容确实有用也是面试会问到的基础,所以这门课很重要的还是,只可惜我是预习了一两天就参加考试了 对了我们的教材是《软件工程体系...
  • 拓扑结构的解释

    万次阅读 2018-03-15 21:31:27
    什么是拓扑结构? 首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体抽象成与其大小、形状无关的“点”,而把连接实体的线路抽象成“线”,进而以图的形式来表示这些点与线之间关系的方法,其目的在于研究这些...
  • 面向过程编程:结构化编程

    千次阅读 2018-11-28 09:38:54
    结构化程式设计(英语:Structured programming),是一种编程典范。也是一种解决问题的思想和方法。它采用子程序、程式码区块 (英语:block structures)、for循环以及while循环等结构,来取代传统的 goto。希望借此来...
  • 程序设计精髓:从 API、UI、结构到商业产品」,「阅读原文」查看交流实录 「文末高能」 编辑 | 朝伟 当下,Android、Linux、Mac 等设备也大行其道,PC 软件似乎已经日薄西山。 然而,我们大多数人平常工作、...
  • java是一种结构化编程

    千次阅读 2020-03-01 19:24:14
    一、结构化程式设计(英语:Structured programming)是 1960 年代开始发展起来的一种编程典范。它采用子程序、 程式码区块、for 循环以及 while 循环等结构来取代传统的 goto。希望借此来改善计算机程序的明晰、品质...
  • 结构化编程(英语:Structured programming),一种编程典范。它采用子程序、程序码区块(英语:block structures)、for循环以及while循环等结构,来取代传统的 goto。希望借此来改善计算机程序的明晰、品质以及...
  • 文中分析认为Google集群针对Web搜索需求的特征,用低成本实现了高可用、高性能集群的方法是并行机设计、开发一个成功典范,这种严格追求价比的设计方法值得借鉴。 关键词:Google 集群 系统结构 文件系统 可靠 可...
  • 我们对牛顿-卡丹背景下的非相对论粒子进行规范分析。 然后,我们将此分析扩展到同一背景下非相对论超粒子的情况。 我们确定该理论的约束结构,并找到κ-对称的产生器。
  • 计算机网络拓扑结构

    千次阅读 2017-03-10 22:16:58
    互联网时代已经到来了,下面学习啦小编为您科普一下网络相关基础知识《什么是拓扑结构》,让您更快融入互联网时代,希望对您有所帮助! 什么是拓扑结构?  首先我们来解释一下拓扑的含义,所谓“拓扑”就是把实体...
  • 在完整、安全、可靠、可管理、可扩展以及可用等方面具有领先地位,Oracle数据库不断地丰富发展,成为当前大型关系数据库中的典范,同时也成为一个庞大的系统软件,Oracle数据库体系结构涉及的内容广泛,又是...
  • C++的程序设计典范

    千次阅读 2003-06-30 09:33:00
     计算机语言程序设计自从50年代中期至今,历经了将近半个世纪,其中经历了无数的挫折,更可喜的是语言的发展取得了重大的进步,其中发展了4中程序设计典范,在计算机的发展史上留下了光辉的一页。一、过程式程序...
  • AG272---低成本CPLD典范

    2020-01-14 14:05:54
    —即时,非易失标准兼容体系结构。 —全局时钟网络中最多有4条全局时钟线驱动整个设备。 —提供可编程的快速传播延迟和时钟至输出时间。 —为每个器件提供PLL,时钟乘法和相移。 —UFM支持高达256 Kbit的非易失...
  • 原PDF下载:http://hums.ccnu.edu.cn/teachers/yyjcai/TR/TR-2005-04.pdfGoogle Linux Cluster的系统结构分析 余一娇1,2 (1华中师范大学语言学系 武汉430079) (2华中科技大学计算机学院 武汉 430074) E-mail: ...
  • 我们不得不承认,Jupyternotebook确实是一款非常棒的工具,它不仅加入了探索数据分析功能,也开辟了整个软件工艺界的典范。 现代软件行业非常了解如何保持代码基础整洁。为了进行结构化,代码基础将首先被分为...
  • 《数据结构与算法Python语言描述》裘宗燕 笔记系列 该系列笔记结合PPT的内容整理的,方便以后复习,有需要的朋友可以看一下。 源码重新整理了 地址:https://github.com/StarsAaron/DS/tree/master   理解三个...
  • 简单地说,若是在一个函数、过程或数据结构的定义中又应用了它本身,则这个函数、过程或数据结构称为是递归定义的,简称递归。 可以参照博主关于斐波那契数列的一些描述和相应代码。 2、队列的应用 2.1、队列在层次...
  • 个性化推荐系统的基本结构个性化推荐系统简介传统推荐策略信息过载推荐系统基本结构物料库召回层规则召回Embedding的流行协同过滤与item CF用户聚类和user CF序列化推荐冷启动的召回排序层粗排序精排序重排序指标与...
  • 在具体学习参考模型每一层的功能的时候,首先要搞清楚层次设计的典范,和每一层设计的原则。 体系结构的含义 简单来说,体系结构的含义就是各层及其协议的集合。比如OSI参考模型分为七层的设计,从数据链路层到应用...
  • 多核体系结构的发展

    千次阅读 2009-05-15 00:27:00
    随着芯片制造工艺的不断进步,从体系结构来看,传统的处理器体系结构技术已面临瓶颈,晶体管的集成度已超过上亿个,很难单纯地通过提高主频来提升性能,而且主频的提高同时也带来功耗的提高。所以并行计算技术应用而...
  • 2018的典范雇主普遍认同人工智能与大数据已经对企业自身与所处行业均发生了深远的影响,并认识到深度学习与赋能型管理的重要,近八成典范雇主通过自建数字化平台介绍前沿或高端知识趋势,以此提高雇员专项技能与...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,803
精华内容 4,721
关键字:

典范性结构