myJavaBlog

java世界
随笔 - 43, 文章 - 0, 评论 - 2, 引用 - 0
数据加载中……

教你如何十步优化JQuery

之 前,我们减少字节数和请求次数以及加载顺序以使页面加载的更快。如今,我们越来越多的注意到另一个影响网站性能的部分--CPU利用率。使用 jQuery和其他JavaScript框架,使节点选择和DOM操作变得越来越容易,如果使用不当,有可能影响整个网页的响应速度,下面列举11个更有 效的使用jQuery库: 
(转 载请注明出处:[url=http://www.live588.org]淘金盈[/url] [url=http://www.tswa.org]博彩通[/url]  [url=http://www.nsdm.org]澳门博彩[/url]  [url=http://www.lixx.org]博彩网[/url][url=http://www.uvip.org]e世博[/url] [url=http://www.10086money.com]时尚资讯[/url][url=http://262002954-qq- com.iteye.com]flex[/url][url=http://flexflex.iteye.com]flex[/url])
1、总是使用#id去寻找element. 

在jQuery中最快的选择器是ID选择器 ($('#someid')). 这是因为它直接映射为JavaScript的getElementById()方法。 
选择单个元素 

Java代码 
  1. <div id="content">  
  2.   
  3.     <form method="post" action="/">  
  4.   
  5.         <h2>Traffic Light</h2>  
  6.   
  7.         <ul id="traffic_light">  
  8.   
  9.             <li><input type="radio" class="on" name="light" value="red" /> Red</li>  
  10.   
  11.             <li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>  
  12.   
  13.             <li><input type="radio" class="off" name="light" value="green" /> Green</li>  
  14.   
  15.         </ul>  
  16.   
  17.         <input class="button" id="traffic_button" type="submit" value="Go" />  
  18.   
  19.     </form>  
  20.   
  21. </div>  




选择button的性能不好的一种方式: 

var traffic_button = $('#content .button'); 

取而代之的是直接选择button: 

var traffic_button = $('#traffic_button'); 

选择多个元素 

在我们讨论选择多个元素的时候,我们真正需要知道的是DOM的遍历和循环才是性能低下的原因。为了尽量减少性能损失, 总是使用最近的父ID去寻找。 

var traffic_lights = $('#traffic_light input'); 
2、在Classes前面使用Tags 

在jQuery中第二快的选择器就是Tag选择器 ($('head')). 而这是因为它直接映射到JavaScript的getElementsByTagName()方法。 

Java代码 
  1. <div id="content">  
  2.   
  3.     <form method="post" action="/">  
  4.   
  5.         <h2>Traffic Light</h2>  
  6.   
  7.         <ul id="traffic_light">  
  8.   
  9.             <li><input type="radio" class="on" name="light" value="red" /> Red</li>  
  10.   
  11.             <li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li>  
  12.   
  13.             <li><input type="radio" class="off" name="light" value="green" /> Green</li>  
  14.   
  15.         </ul>  
  16.   
  17.         <input class="button" id="traffic_button" type="submit" value="Go" />  
  18.   
  19.     </form>  
  20.   
  21. </div>  




总是在一个Class前面加上一个tag名字(记得从一个ID传下来) 

var active_light = $('#traffic_light input.on');注意:在jQuery里Class选择器是最慢的一个选择器;在IE中它循环整个DOM。可能的话尽量避免使用它。不要在ID前面 加Tags。例如,它会因为去循环所有的<div>元素去寻找ID为content的<div>,而导致很慢。 

var content = $('div#content');按照同样的思路,从多个ID传下来是冗余的。 

var traffic_light = $('#content #traffic_light'); 
3、缓存jQuery对象 

养成保存jQuery对象到一个变量上(就像上面的例子)的习惯。例如,不要这样做: 

$('#traffic_light input.on).bind('click', function(){...}); 

$('#traffic_light input.on).css('border', '3px dashed yellow'); 

$('#traffic_light input.on).css('background-color', 'orange'); 

$('#traffic_light input.on).fadeIn('slow'); 

取而代之,首现保存jQuery变量到一个本地变量后,再继续你的操作。 

var $active_light = $('#traffic_light input.on'); 

$active_light.bind('click', function(){...}); 

$active_light.css('border', '3px dashed yellow'); 

$active_light.css('background-color', 'orange'); 

$active_light.fadeIn('slow'); 

提示:使用$前辍表示我们的本地变量是一个jQuery包集。记住,不要在你的应该程序里出现一次以上的jQuery重复的选择操作。 额外提示:延迟存储jQuery对象结果。 

如果你想在你的程序的其它地方使用jQuery结果对象(result object(s)),或者你的函数要执行多次,要把它缓存在一个全局范围的对象里。通过定义一个全局容器保存jQuery结果对象,就可以在其它的函数里引用它。 

// Define an object in the global scope (i.e. the window object) 

window.$my ={ 

    // Initialize all the queries you want to use more than once 

    head : $('head'), 

    traffic_light : $('#traffic_light'), 

    traffic_button : $('#traffic_button')}; 

function do_something(){ 

    // Now you can reference the stored results and manipulate them 

    var script = document.createElement('script'); 

    $my.head.append(script); 

    // When working inside functions, continue to save jQuery results 

    // to your global container. 

    $my.cool_results = $('#some_ul li'); 

    $my.other_results = $('#some_table td'); 

    // Use the global functions as you would a normal jQuery result 

    $my.other_results.css('border-color', 'red'); 

    $my.traffic_light.css('border-color', 'green'); 


4、更好的利用链 

前面的例子也可以这样写: 

var $active_light = $('#traffic_light input.on'); 

$active_light.bind('click', function(){...}) 

    .css('border', '3px dashed yellow') 

    .css('background-color', 'orange') 

   .fadeIn('slow'); 

这样可以让我们写更少的代码,使JavaScript更轻量。 


5、使用子查询 

jQuery允许我们在一个包集上附加其它的选择器。因为我们已经在本地变量里保存了父对象这样会减少以后在选择器上的性能开销。 

<div id="content"> 

    <form method="post" action="/"> 

        <h2>Traffic Light</h2> 

        <ul id="traffic_light"> 

            <li><input type="radio" class="on" name="light" value="red" /> Red</li> 

            <li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li> 

            <li><input type="radio" class="off" name="light" value="green" /> Green</li> 

        </ul> 

        <input class="button" id="traffic_button" type="submit" value="Go" /> 

    </form> 

</div> 

例如,我们可以利用子查询缓存active和inactive lights以便后面的操作。 

var $traffic_light = $('#traffic_light'),   

$active_light = $traffic_light.find('input.on'),   

$inactive_lights = $traffic_light.find('input.off'); 

提示:可以用逗号隔开一次定义多个本地变量,这样可以节省一些字节。 


6、限制直接对DOM操作 

DOM操作的基本做法是在内存中创建DOM结构,然后再更新DOM结构。这不是jQuery最好的做法,但对JavaScript来讲是高效的。直接操作DOM结构性能是低下的。 例如,如果你需要动态创建一列元素,不要这样做: 

var top_100_list = [...], // assume this has 100 unique strings   

$mylist = $('#mylist'); // jQuery selects our <ul> element 

for (var i=0, l=top_100_list.length; i<l; i++){   

    $mylist.append('<li>' + top_100_list[i] + '</li>'); 



取而代之,我们希望在插入DOM结构之前先在一个字符串里创建一套元素。 
代码 

var top_100_list = [...], // assume this has 100 unique strings   

$mylist = $('#mylist'), // jQuery selects our <ul> element   

top_100_li = ""; // This will store our list items 

for (var i=0, l=top_100_list.length; i<l; i++){ 

    top_100_li += '<li>' + top_100_list[i] + '</li>'; 



$mylist.html(top_100_li); 

更快的做法,在插入DOM结构之前我们应该总是在一个父节点里包含许多元素 

var top_100_list = [...], // assume this has 100 unique strings   

$mylist = $('#mylist'), // jQuery selects our <ul> element   

top_100_ul = '<ul id="#mylist">'; // This will store our entire unordered list 

for (var i=0, l=top_100_list.length; i<l; i++){ 

    top_100_ul += '<li>' + top_100_list[i] + '</li>'; 



top_100_ul += '</ul>'; // Close our unordered list 

$mylist.replaceWith(top_100_ul); 

如是你照着上面的做了还是对性能有些迷惑的话,可以参考以下内容: 

* 试一下jQuery提供的Clone()方法。Clone()方法创建节点数的拷贝,随后你可以在这个副本中进行操作。 

* 使用DOM DocumentFragments. As the creator of jQuery points out, 比直接操作DOM性能上更好. 先创建你需要的结构(就像我们上面用一个字符串做的一样), 然后使用jQuery的 insert or replace methods. 

7、事件委托(又名:冒泡事件) 

除 非特别说明,每一个JavaScript事件(如click, mouseover 等)在DOM结构树上都会冒泡到它的父元素上。如果我们想让很多elements(nodes)调用同一个function这是非常有用的。取而代之的是 你可以只对它们的父级绑定一次,而且可以计算出是哪一个节点触发了事件,而不是绑定一个事件监听器到很多节点上这种效率低下的方式。例如,假如我们要开发 一个包含很多input的大型form,当input被选择的时候我们想绑定一个class name。像这样的帮定是效率低下的: 

$('#myList li).bind('click', function(){ 

    $(this).addClass('clicked');    // do stuff 

}); 

反而,我们应该在父级侦听click事件。 

$('#myList).bind('click', function(e){ 

    var target = e.target, // e.target grabs the node that triggered the event. 

        $target = $(target);  // wraps the node in a jQuery object 

    if (target.nodeName === 'LI') { 

        $target.addClass('clicked');        // do stuff 

    } 

}); 

父节点担当着发报机的工作,可以在触发了事件的目标element上做一些工作。如果你发现自己把一个event listener帮定到很多个element上,那么你这种做法是不正确的。 

8、消除查询浪费 

虽 然jQuery对没有找到任何匹配的elements处理的很好,但是它还是需要花费时间去查找的。如果你的站点有一个全局的JavaScript,你可 能会把每个jQuery function都放在 $(document).ready(function(){ // all my glorious code })里。不要这样做。只去放一些页面上适合用到的function。这样做最有效的方式是你的模板可以完全控制任何时候或者地方执行JavaScript 以内联脚本的方式初始化function。例如,在你的“article”页面模板里,你可能在body标签关闭之前包含以下代码 

<script type="text/javascript>mylib.article.init();</script></body& gt;如果你的页面模板包含多种有可能在页面或者不在页面上的模块,或者为了可视化效果你需要它们稍后再初如化,你应该在这些模块之后立即放置初如化函 数。

<ul id="traffic_light"> 

    <li><input type="radio" class="on" name="light" value="red" /> Red</li> 

    <li><input type="radio" class="off" name="light" value="yellow" /> Yellow</li> 

    <li><input type="radio" class="off" name="light" value="green" /> Green</li> 

</ul> 

<script type="text/javascript>mylib.traffic_light.init();</script> 

你的全局JavaScript库看起来应该是这样的: 

var mylib ={ 

    article_page :    { 

        init : function()        { 

            // Article page specific jQuery functions. 

       } 

    }, 

   traffic_light :    { 

        init : function()        { 

            // Traffic light specific jQuery functions. 

       } 

    } 



9、遵从$(windows).load 

有 一种诱惑会使jQuery开发者hook所有事情到 $(document).ready 这个虚伪的事件里。毕竟在大多数例子里都可以看到这样使用。虽然$(document).ready 非常有用,它在页面呈现时发生,虽然其它对象还在下载中。如果你发现你的页面在下载中停顿,就有可能是$(document).ready 引起的。你可以通过把jQuery functions帮定到$(window).load事件来减少下面下载时的CPU使用率,它是在所有HTML(包括iframe内容)都下载完以后才 去调用所有对象的。 

$(window).load(function(){ 

    // jQuery functions to initialize after the page has loaded. 

}); 

多余的功能,如拖拽、帮定可视化效果和动画、预读取图片等,使用这种方法比较好。 



10、压缩JS 

虽 然和jQuery无关,但在这里也要提一下。使JavaScript函数和变量变得可读是一个趋势,这对开发者来讲是必不可少的,但对普通用户来讲没有任 何关系。不用什么借口,是时候把JS压缩纳入我们的工作流程中来了。注释你的代码,在投放到生产环境之前找一个压缩工具进行压缩。使用 YUICompressor 压缩你代码中多余的浪费的字节。根据我们的经验,它可以安全的把JavaScript压缩的尽可能小,而不会多占用CPU。小提示:为了在 YUICompressor里最大化压缩,应该这样这样定义变量(例如:var my_long_variable_name;) 



11、学习jQuery API库文档 

学习和最有效的使用jQuery,最好的方法就是去查jQuery的文档了,可以当作手册来用。

(转载请注明出处:[url=http://www.k8764.com]博彩通[/url][url=http://www.5sfd.com]e世博[/url][url=http://www.6rfd.com]澳门博彩[/url])

posted @ 2012-04-16 23:45 夏凡 阅读(167) | 评论 (0)编辑 收藏

【超详细】flex入门学习全攻略

原来有人问我:怎样学好Flash?我的回答一般就是:仔细看帮助、多做练习、多看优秀的源码、多上专业论坛参加讨论。

可是Flex来了,于是又有人问:怎样学好Flex?

我不知如何回答,因为我也是Flex新手,也在“仔细看帮助、做练习、看源码、上论坛……”。现在d.CAT的这篇优秀的文章,详细的回答了这个问题。

下面的文章转自d.CAT RIA Blog,由于原文是繁体中文的,所以转载过来的时候我对文章的繁体字部分进行了替换,对一些词语进行了修改以符合简体中文语言习惯,对一些术语进行了注释。

最后,文中所有第一人称处所指的都是原文作者而不是“我”,有麻烦可以找他 

以下为转载:
==================================================================

Flex 的基础架构

关于 flex 基本上常被问到的不外乎就是“如何可以学好它?”,要了解这个问题的答案基本上只要看懂下面这个图就OK了。

<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" alt="Flex 的基础架构" style='width:412.5pt;height:300pt'> <v:imagedata src="file:///C:\DOCUME~1\YUANQI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image002.jpg" o:href="http://www.51as.com/upup/image/Article/2007/12/28/40433992.gif" /> </v:shape><![endif]--><!--[if !vml]-->Flex 的基础架构<!--[endif]-->

Actionscript 该学的重点

从最底层看起,最下面的 actionscript 3是一切的基础,它是 flash/flex 编程使用的唯一程式语言,因此任何人想学好 flex 第一件事绝对是先摸熟 actionscript 这个语言,包含:

<!--[if !supportLists]-->1.<!--[endif]-->它的基本语法与结构(array, hash, loop, if else…)

<!--[if !supportLists]-->2.<!--[endif]-->DisplayList (DisplayObject, DisplayObjectContainer)与 Event system(bubbling, propagating…)

<!--[if !supportLists]-->3.<!--[endif]-->Sound, Video, NetConnection 与 Graphics class

掌握 as3 的精华后,接下来就可以进入 flex framework。

Flex framework 的重点

基本上 flex framework 就是用 actionscript 写成的框架,因此也可以把它看成是 as3的最好示范,看着 framework source 学 actionscript 也是挺不错的,只是路会变很长。

Flex Framework 整个体系非常博大精深,通常一般人不太可能完整把它学完,只需要针对最常用到的部份熟悉就好,图中列出的那三块(component, managers, style/skin)就是我个人认为所有初学者最优先该学会的。

Component 该学些什么

Component 是整个 flex framework 的基础,几乎80% 的元素都是由 UIComponent 继承而来,例如最根本的它本身就是一个 UIComponent,因此,熟悉 component 就成为学好 flex framework 最根本也最重要的基本功

Flex 内建了 二十几个 UI controls, 例如 Button, DataGrid, HBox等,以种类来分,这些 components 可以概分为三大类:

<!--[if !supportLists]-->·    <!--[endif]-->Controls: Button, DateChooser, Slider…

<!--[if !supportLists]-->·    <!--[endif]-->Containers: Box, DividedBox, Panel…

<!--[if !supportLists]-->·    <!--[endif]-->List: DataGrid, Tree, TileList…

初学者第一步至少该学会怎么用这些元件,了解每个元件的 properties, events, styles, effects…,知道怎么在手册里查它的 API 文件,以及何时该用何种元件。

进一步,则是学会怎么修改这些元件,例如继承一个 Button 下来加上不同的功能,或是写不同的 skin border 来改变它的外观。

再进一步,则是开始研究元件的生命周期,了解每个元件是何时初始化,元件内部有那些关键指令与它们个别的功能,然后可以试着建立自已的 custom component。

这一关看起来容易但实际上最困难,因为 flex 的 component framework 写的非常庞大,虽然乱中有序但要在混沌中看出隐藏的架构然后抓住重点整串提起,就非得有人带着指引正确的途径才比较可能完成。

manager 是什么

图中最上方的第二块就是 manager。

flex 里有很多的 managers,负责做各种不同的工作(废话…),几个比较重要的包含:

<!--[if !supportLists]-->·    <!--[endif]-->SystemManager:
它是每个 flex 程序的根源,最先被下载,也最早启动,由它进行一连串的 app boot流程

<!--[if !supportLists]-->·    <!--[endif]-->StyleManager:
它负责整支app 的 css style 套用与 skin 生成,如果想玩动态 css 载换也靠它

<!--[if !supportLists]-->·    <!--[endif]-->DragManager:
Flex
最大的卖点就是 drag and drop(拖放),这个 manager 就是背后的英雄,初学者至少要学会怎么处理 drag 行为的五个事件,以及如何在不同元件间做拖放;进阶的玩家则应该深入研究这支 manager 是怎么写成的,详细阅读它的 source 会得到意想不到的无穷乐趣(如果你读完却没有这种感觉,呃,那代表你该再多读几次,如果还是没有,那请私下联络我 <!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" alt=":D" style='width:12pt;height:12pt'> <v:imagedata src="file:///C:\DOCUME~1\YUANQI~1\LOCALS~1\Temp\msohtmlclip1\01\clip_image003.gif" o:href="http://www.51as.com/upup/image/Article/2007/12/28/40433993.gif" /> </v:shape><![endif]--><!--[if !vml]-->:D<!--[endif]-->)

<!--[if !supportLists]-->·    <!--[endif]-->ModuleManager:
使用 Flex 开发大型应用程式时,往往会将程式切割成许多小的 module, 这个 manager 就是负责载入并管理所有的 module (包含它的 class partition),初心者或许用不到,但有志深入的玩家一定要很熟。

<!--[if !supportLists]-->·    <!--[endif]-->CursorManager:
这个用到的时机不是很多,但偶尔要换一下 cursor 时还是会用到,初学者至少要知道怎么用指定的图案去换掉系统cursor。

Style/Skin 的重点

CSS style skinning 是 Flex 最大的卖点之一,也是开发过程中较为麻烦也最耗时的部份。

初学者应该要彻底了解如何使用 CSS style 来打点一支 flex app 的外观,换颜色、素材,使用外部 assets 修饰介面。

中阶玩家则应该了解 skinning 的系统,包含 programmatic skinning 与 graphical skin,它们俩的差别?使用时机?如何客制化(zrong注1)?

更高阶的玩家则应该熟悉整个 Styling system 的运作模式,外加如何动态载入 css 在 runtime 换掉整个介面。

简而言之,flex app 写的好不好,外行人其实看不太出来,但一支 app UI 美不美则是一翻两瞪眼,比较漂亮的那就先加十分

(当然,有一种情况是刻意用心去美化了介面结果弄巧成拙搞的怨声载道人人喊打,但那种比较不多见,也不是每家公司都会搞到这步田地,就先不讨论)

*学完基本功后下一步

在我的标准里,当一个 developer 对上图内每一块都有中等程度的了解后,就算是完成 flex 养成教育,可以迈向下一个阶段。

也就是开始熟悉 application 的制作手法,这包含

<!--[if !supportLists]-->·    <!--[endif]-->了解至少一种以上的开发框架,例如 Cairngorm,老实说我对这个框架没什么好感(因为手法太复杂,只适合超复杂登月计画或火星探勘时使用),但它结构设计良好,又是业界公认的圣杯,等于是专家们共通的语言,因此至少要先了解它在做什么,将来在专业场合才好沟通(俗话说 know the rules so you know what you are breaking, 就是指这情况)

<!--[if !supportLists]-->·    <!--[endif]-->接着可以看看比较简单的手法,像 Riawave, Model-Glue:Flex, PureMVC…等,基本上这些框架设计方式都大同小异,每个都有不同的应用场合,可以挑一个喜欢的再自行修改。

<!--[if !supportLists]-->·    <!--[endif]-->了解基本的概念,例如 Value Object, DAO, MVC 等,它们在大部份的程式框架里都会出现,早点学会日子比较轻松。

<!--[if !supportLists]-->·    <!--[endif]-->接着就是开始实际 coding,写一个中小型规模的app,不论是单纯的 CRUD (zrong注2)程序,或是留言版、电话簿、进销存管理都可以,籍由多写来强化编程的概念,然后透过大量的 peer code review 来找出可改进的地方。

*结论

结论还是老话一句:要入门 flex 超级简单,只要不是白痴应该一小时就行,但要成为可独当一面的专业开发者,路就很长,如果没有走对方向很容易就迷失甚至最后放弃。

换句话说,要能成为职场上真正需要的 professional developer,并不如表面上想象的容易(其实我想每种技术领域跟产业都一样吧),这也是我过去半年来协助很多公司做 recruiting 后的感想。

zrong注1:按客人要求不同定义
zrong
注2:CRUD是指在做计算处理时的增加、查询(重新得到数据)、更新和删除(create, retrieve, update, and delete)几个单词的首字母简写。主要被用在描述软件系统中数据库或者持久层的基本操作功能。

(转载请注明出处:[url=http://www.a9832.com]博彩网[/url][url=http://www.tswa.org]博彩通[/url][url=http://www.k6567.com]e世博[/url])

posted @ 2012-04-16 21:59 夏凡 阅读(118) | 评论 (0)编辑 收藏

android开发性能优化总结

性能优化

Android应用程序运行的移动设备受限于其运算能力,存储空间,及电池续航。由此,它必须是高效的。电池续航可能是一个促使你优化程序的原因,即使他看起来已经运行的足够快了。由于续航对用户的重要性,当电量耗损陡增时,意味这用户迟早会发现是由于你的程序。

虽然这份文档主要包含着细微的优化,但这些绝不能成为你软件成败的关键。选择合适的算法和数据结构永远是你最先应该考虑的事情,但这超出这份文档之外。



简介

写出高效的代码有两条基本的原则:

* 不作没有必要的工作。

* 尽量避免内存分配。



明智的优化

这份文档是关于Android规范的细微优化,所以先确保你已经了解哪些代码需要优化,并且知道如何去衡量你所做修改所带来的效果(好或坏)。开发投入的时间是有限的,所以明智的时间规划很重要。

(更多分析和笔记参见总结。)

这份文档同时确保你在算法和数据结构上作出最佳选择的同时,考虑API选择所带来的潜在影响。使用合适的数据结构和算法比这里的任何建议都更有价值,优先考虑API版本带来的影响有助于你找到更好的实现。(这在类库代码中更为重要,相比应用代码)

(如果你需要这样的建议,参见 Josh Bloch's Effective Java, item 47.)

在 优化Android程序时,会遇到的一个棘手问题是,保证你的程序能在不同的硬件平台上运行。虚拟机版本和处理器各部相同,因此运行在之上的速度也大不一 样。但这并且不是简单的A比B快或慢,并能在设备间做出排列。特别的,模拟器上只能评测出一小部分设备上体现的东西。有无JIT的设备间也存在着巨大差 异,在JIT设备上好的代码有时候会在无JIT的设备上表现的并不好。

如果你想知道一个程序在设备上的具体表现,就必须在上面进行测试。



避免创建不必要的对象

对象创建永远不会是免费的。每个线程的分代GC给零时对象分配一个地址池以降低分配开销,但往往内存分配比不分配需要的代价大。

如果在用户界面周期内分配对象,就会强制一个周期性的垃圾回收,给用户体验增加小小的停顿间隙。Gingerbread中提到的并发回收也许有用,但不必要的工作应当被避免的。

因此,应该避免不必要的对象创建。下面是几个例子:

* 如果有一个返回String的方法,并且他的返回值常常附加在一个StringBuffer上,改变声明和实现,让函数直接在其后面附加,而非创建一个短暂存在的零时变量。

* 当从输入的数据集合中读取数据时,考虑返回原始数据的子串,而非新建一个拷贝.这样你虽然创建一个新的对象,但是他们共享该数据的char数组。(结果是即使仅仅使用原始输入的一部分,你也需要保证它的整体一直存在于内存中。)

一个更彻底的方案是将多维数组切割成平行一维数组:

* Int类型的数组常有余Integer类型的。推而广之,两个平行的int数组要比一个(int,int)型的对象数组高效。这对于其他任何基本数据类型的组合都通用。

* 如果需要实现一个容器来存放元组(Foo,Bar),两个平行数组Foo[],Bar[]会优于一个(Foo,Bar)对象的数组。(例外情况是:当你设计API给其他代码调用时,应用好的API设计来换取小的速度提升。但在自己的内部代码中,尽量尝试高效的实现。)

通常来讲,尽量避免创建短时零时对象.少的对象创建意味着低频的垃圾回收。而这对于用户体验产生直接的影响。



性能之谜

前一个版本的文档给出了好多误导人的主张,这里做一些澄清:

在 没有JIT的设备上,调用方法所传递的对象采用具体的类型而非接口类型会更高效(比如,传递HashMap map比Map map调用一个方法的开销小,尽管两个map都是HashMap).但这并不是两倍慢的情形,事实上,他们只相差6%,而有JIT时这两种调用的效率不相 上下。

在没有JIT的设备上,缓存后的字段访问比直接访问快大概20%。而在有JIT的情况下,字段访问的代价等同于局部访问,因此这里不值得优化,除非你觉得他会让你的代码更易读(对于final ,static,及static final 变量同样适用)



用静态代替虚拟

         如果不需要访问某对象的字段,将方法设置为静态,调用会加速15%到20%。这也是一种好的做法,因为你可以从方法声明中看出调用该方法不需要更新此对象的状态。



避免内部的Getters/Setters

在源生语言像C++中,通常做法是用Getters(i=getCount())代替直接字段访问(i=mCount)。这是C++中一个好的习惯,因为编译器会内联这些访问,并且如果需要约束或者调试这些域的访问,你可以在任何时间添加代码。

而在Android中,这不是一个好的做法。虚方法调用的代价比直接字段访问高昂许多。通常根据面向对象语言的实践,在公共接口中使用Getters和Setters是有道理的,但在一个字段经常被访问的类中宜采用直接访问。

无JIT时,直接字段访问大约比调用getter访问快3倍。有JIT时(直接访问字段开销等同于局部变量访问),要快7倍。在Froyo版本中确实如此,但以后版本可能会在JIT中改进Getter方法的内联。



对常量使用Static Final修饰符

考虑下面类首的声明:


编译器会生成一个类初始化方法<clinit>,当该类初次被使用时执行,这个方法将42存入intVal中,并得到类文件字符串常量strVal的一个引用。当这些值在后面被引用时,他们通过字段查找进行访问。

我们改进实现,采用 final关键字:


类 不再需要<clinit>方法,因为常量通过静态字段初始化器进入dex文件中。引用intVal的代码,将直接调用整形值42;而访问 strVal,也会采用相对开销较小的“字符串常量”(原文:“sring constant”)指令替代字段查找。(这种优化仅仅是针对基本数据类型和String类型常量的,而非任意的引用类型。但尽可能的将常量声明为 static final是一种好的做法。



使用改进的For循环语法

改进for循环(有时被称为 “for-each”循环)能够用于实现了iterable接口的集合类及数组中。在集合类中,迭代器让接口调用hasNext()和next()方法。 在ArrayList中,手写的计数循环迭代要快3倍(无论有没有JIT),但其他集合类中,改进的for循环语法和迭代器具有相同的效率。

这里有一些迭代数组的实现:


zero()是当中最慢的,因为对于这个遍历中的历次迭代,JIT并不能优化获取数组长度的开销。

One()稍快,将所有东西都放进局部变量中,避免了查找。但仅只有声明数组长度对性能改善有益。

Two()是在无JIT的设备上运行最快的,对于有JIT的设备则和one()不分上下。他采用了JDK1.5中的改进for循环语法。

结论:优先采用改进for循环,但在性能要求苛刻的ArrayList迭代中,考虑采用手写计数循环。

(参见 Effective Java item 46.)



在私有内部内中,考虑用包访问权限替代私有访问权限

考虑下面的定义:


需要注意的关键是:我们定义的一个私有内部类(Foo$Inner),直接访问外部类中的一个私有方法和私有变量。这是合法的,代码也会打印出预期的“Value is 27”。

但问题是,虚拟机认为从Foo$Inner中直接访问Foo的私有成员是非法的,因为他们是两个不同的类,尽管Java语言允许内部类访问外部类的私有成员,但是通过编译器生成几个综合方法来桥接这些间隙的。


内部类会在外部类中任何需要访问mValue字段或调用doStuff方法的地方调用这些静态方法。这意味着这些代码将直接存取成员变量表现为通过存取器方法访问。之前提到过存取器访问如何比直接访问慢,这例子说明,某些语言约会定导致不可见的性能问题。

如果你在高性能的Hotspot中使用这些代码,可以通过声明被内部类访问的字段和成员为包访问权限,而非私有。但这也意味着这些字段会被其他处于同一个包中的类访问,因此在公共API中不宜采用。



合理利用浮点数

通常的经验是,在Android设备中,浮点数会比整型慢两倍,在缺少FPU和JIT的G1上对比有FPU和JIT的Nexus One中确实如此(两种设备间算术运算的绝对速度差大约是10倍)

从速度方面说,在现代硬件上,float和double之间没有任何不同。更广泛的讲,double大2倍。在台式机上,由于不存在空间问题,double的优先级高于float。

但即使是整型,有的芯片拥有硬件乘法,却缺少除法。这种情况下,整型除法和求模运算是通过软件实现的,就像当你设计Hash表,或是做大量的算术那样。



了解并使用类库

         选择Library中的代码而非自己重写,除了通常的那些原因外,考虑到系统空闲时会用汇编代码调用来替代library方法,这可能比JIT中生成的等 价的最好的Java代码还要好。典型的例子就是String.indexOf,Dalvik用内部内联来替代。同样的,System.arraycopy 方法在有JIT的Nexus One上,自行编码的循环快9倍。

         (参见 Effective Java item 47.)



合理利用本地方法

本 地方法并不是一定比Java高效。最起码,Java和native之间过渡的关联是有消耗的,而JIT并不能对此进行优化。当你分配本地资源时(本地堆上 的内存,文件说明符等),往往很难实时的回收这些资源。同时你也需要在各种结构中编译你的代码(而非依赖JIT)。甚至可能需要针对相同的架构来编译出不 同的版本:针对ARM处理器的GI编译的本地代码,并不能充分利用Nexus One上的ARM,而针对Nexus One上ARM编译的本地代码不能在G1的ARM上运行。

当你想部署程序到存在本地代码库的Android平台上时,本地代码才显得尤为有用,而并非为了Java应用程序的提速。

(参见 Effective Java item 54.)



结语

最后:通常考虑的是:先确定存在问题,再进行优化。并且你知道当前系统的性能,否则无法衡量你进行尝试所得到的提升。

这份文档中的每个主张都有标准基准测试作为支持。你可以在code.google.com“dalvik”项目中找到基准测试的代码。

这 个标准基准测试是建立在Caliper Java标准微基准测试框架之上的。标准微基准测试很难找到正确的路,所以Caliper帮你完成了其中的困难部分工作。并且当你会察觉到某些情况的测试 结果并想象中的那样(虚拟机总是在优化你的代码的)。我们强烈推荐你用Caliper来运行你自己的标准微基准测试。

同时你也会发现Traceview对分析很有用,但必须了解,他目前是不不支持JIT的,这可能导致那些在JIT上可以胜出的代码运行超时。特别重要的,根据Taceview的数据作出更改后,请确保代码在没有Traceview时,确实跑的快了。

 

(转载请注明出处:[url=http://www.k8764.com]博彩通[/url][url=http://www.5sfd.com]e世博[/url][url=http://www.6rfd.com]澳门博彩[/url])

posted @ 2012-04-16 21:55 夏凡 阅读(198) | 评论 (0)编辑 收藏

仅列出标题
共5页: 上一页 1 2 3 4 5