第一篇:網站前端性能優化總結
一、服務器側優化
1.添加 Expires 或 Cache-Control 信息頭
某些經常使用到、并且不會經常做改動的圖片(banner、logo等等)、靜態文件(登錄首頁、說明文檔等)可以設置較長的有效期(expiration date),這些HTTP頭向客戶端表明了文檔的有效性和持久性。如果有緩存,文檔就可以從緩存(除已經過期)而不是從服務器讀取。接著,客戶端考察緩存中的副本,看看是否過期或者失效,以決定是否必須從服務器獲得更新。
各個容器都有針對的方案,,以 Apache 為例:
ExpiresActive On ExpiresByType image/gif “access plus 1 weeks”
表示gif文件緩存一周,配置可以根據具體的業務進行調整,具體配置可以參考:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_expires.html
2.壓縮內容
對于絕大多數站點,這都是必要的一步,能有效減輕網絡流量壓力。
表示zlib在壓縮時可以最大程度的使用內存,壓縮html、文本、xml和php這幾種類型的文件,指定擴展名為html、htm、xml、php、css和js的文件啟用壓縮。
具體配置可以參考:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_deflate.html
3.設置 Etags
在使用etags之前,有必要復習一下 RFC2068 中規定的返回值 200 和 304 的含義:
200--OK 304--Not Modified
客戶端在請求一份文件的時候,服務端會檢查客戶端是否存在該文件,如果客戶端不存在該文件,則下載該文件并返回200;如果客戶端存在該文件并且該文件在規定期限內沒有被修改(Inode,MTime和Size),則服務端只返回一個304,并不返回資源內容,客戶端將會使用之前的緩存文件。而etags就是判斷該文件是否被修改的記號,與服務器端的資源一一關聯,所以etags對于CGI類型的頁面緩存尤其有用。
下圖是優化前的首頁:(注意,此時沒有壓縮首頁圖片,即使使用了緩存,仍需要5s左右的時間)
化前的某頁面
需要注意的是,使用etags會增加服務器端的負載,在實際應用中需要自行平衡。
二、Cookie優化
1.減小Cookie體積
HTTP coockie可以用于權限驗證和個性化身份等多種用途。coockie內的有關信息是通過HTTP文件頭來在web服務器和瀏覽器之間進行交流的。因此保持coockie盡可能的小以減少用戶的響應時間十分重要。
使cookie體積盡量小;
在合適的子域名上設置bookie,以免影響其他子域名下的響應;
設置合理的過期時間,去掉不必要的cookie。
下面對比一下各個網站的cookie:
圖中可以看出,6K的cookie顯然是不必要的。
2.對于頁面內容使用無coockie域名
當瀏覽器在請求中同時請求一張靜態的圖片和發送coockie時,服務器對于這些coockie不會做任何地使用。因此它們只是因為某些負面因素而創建的網絡傳輸。所以你應該確定對于靜態內容的請求是無coockie的請求。創建一個子域名并用他來存放所有靜態內容。
例如,域名是
3.切分組件到多個域
主要的目的是提高頁面組件并行下載能力,但注意,也不要同時使用過多的域名,否則就會出現第一條DNS lookup過多的問題,一般情況下兩個域名就可以了。
4.杜絕 http 404 錯誤
對頁面鏈接的充分測試加上對 Web 服務器 error 日志的不斷跟蹤可以有效減少 404 錯誤,并提升用戶體驗。
后記:
這次總結給我帶來的啟發并不在于提升系統性能性能本身,提升性能只是一個很表面上的東西,網上的方法有很多,測試的方法也有很多,照著都做一遍,性能確實會有所提升,但是這種知其然而不知其所以然的性能提升是沒有意義的,這便是本文的目的所在。
第二篇:Web前端頁面性能優化小結
Web前端頁面性能優化小結
Web前端頁面性能優化小結
影響用戶訪問的最大部分是前端的頁面。網站的劃分一般為二:前端和后臺。我們可以理解成后臺是用來實現網站的功能的,比如:實現用戶注冊,用戶能夠為文章發表評論等等。而前端呢?其實應該是屬于功能的表現。
而我們建設網站的目的是什么呢?不就是為了讓目標人群來訪問嗎?所以我們可以理解成前端才是真正和用戶接觸的。
除了后臺需要在性能上做優化外,其實前端的頁面更需要在性能優化上下功夫,只有這樣才能給我們的用戶帶來更好的用戶體驗。不僅僅如此,如果前端優化得好,他不僅可以為企業節約成本,他還能給用戶帶來更多的用戶,因為增強的用戶體驗。說了這么多,那么我們應該如何對我們前端的頁面進行性能優化呢?
前端的頁面主要包括xhtml,css,js。其實xhtml就是現實中所談到的內容,頁面的內容:文字,圖片,flash,視頻等。
而前端開發工作者可以控制的是什么呢?那就是xhtml,css,js的代碼及相應的修飾(背景)圖片。下面我就根據我自己的經驗來說說:
一、提倡前端開發工程師在書寫xhtml的時候做到結構語義化。結構中主要包括了head和body兩個部分,但是我們經常說的是結構語義化主要是body中的標簽,但是我在這里還是簡單的說一下 head,head中其實包括了一些對于我們seo很有用的一些東西,比如
title,description,keywords,這些東西在蜘蛛抓取的時候都是有幫助的,當然,還有其他的一些,我在此就不一一說明了,比如設置緩存等一些其他的信息。那么body中的話,包括的標簽就很多了,我覺得作為一個合格的前端開發人員你應該去熟悉他們,比如div,span,h,ul,ol,dl,p等等這類的標簽的使用。應該非常合理,還有就是注意h標簽的斷層,及h1標簽的使用,這些都是非常重要的。同時在我們的結構中不要出現style和onclick這樣的內聯的樣式和事件.。希望大家能夠注意結構與表現、行為的分離。(ps:標簽語義化的好處:1.有利于搜索引擎;2.結構清晰的html在團隊合作中的作用,就不必說了吧;3.有利于盲人屏幕閱讀器。至于如何做到標簽語義化,就看個人的理解了,這方面我也覺得模糊,跟個人的習慣估計也有一定的關系,總之鄒惠斌老師是認為我的標簽不語義的。)
二、css(http://zhi.ujiuye.com/web/css/),js文件數量及大小的優化 那么關于css、js的優化的話,一般情況下建議css和js采用外聯式。但是如果你的頁面內容比較多,設計師把整個效果做得比較花的話,恐怕 css就非常多了,那么這種情況下,你一定要把你的css規劃好,盡量的采用縮寫,這樣可以減少css文件的大小,那么對css做相應的規劃也可以減少 css的個數,減少http請求數,js同理。(ps:減少重復性代碼,代碼重復利用,在這里顯得特別重要)
三、背景圖片數量及大小的優化
當我們將設計師的設計稿還原成靜態頁面后,除非頁面所有的修飾全是色塊,內容全是文字,沒有圖片,如果不是這樣的話,那么我們需要對圖片做優化處理。當然內容圖片我們是沒有辦法了,因為他是屬于內容部分的,一般情況是由于編輯處理,當然,我在還是有一個小小的建議,如果我們的網站中需要有內容圖片,希望編輯能夠將他們最優化以后,在進行上傳,一會兒告訴我的方法,下面我在說說,作為前端開發應該如何處理我們的修飾(背景)圖片。由于我們的背景圖片數量比較多,這樣的話,會給服務器帶來影響,增加了http請求數,我們是否有一種好的解決辦法呢?這個答案是肯定的,如果你是一個合格的前端開發,你應該清楚,在我們的css定義背景的時候,可以通過坐標來實現對背景進行定位的,既然如此,那么我們可以將這些背景合并起來,這樣即可減少http請求數,同時,我們在背景整合的時候,也需要考慮圖片質量,同時也需要考慮圖片的大小(ps:這里建議使用png8格式的圖片結合css sprite,同樣的圖片,png8格式會相對來比gif小)
四、內容圖片的大小的優化
其實剛才已經說了內容圖片的問題,那么我在這里呢,告訴大家一個比較簡單的方法,就是使用雅虎提供的一個工具。他就是smushit:http:// 規范在文檔 內加載你的樣式表。
對于擁有較大瀏覽量的首頁來說,有一種技術可以平衡內置代碼帶來的 http 請求減少與通過使用外部文件進行緩存帶來的好處。其中一個就是在首頁中內置 javascript 和 css,但是在頁面下載完成后動態下載外部文件,在子頁面中使用到這些文件時,它們已經緩存到瀏覽器了。
更多知識干貨分享,盡在中公優就業,>>>點擊進入。
點擊查看>>>中公IT優就業封閉式培訓,包食宿,學費貸款,交通補貼,推薦就業
第三篇:計算機系統性能優化總結
計算機系統性能優化總結
現今,計算機技術在社會各行各業都得到了廣泛的應用。計算機給我們的學習、生活和工作都帶來了極大的便利。但隨著我們對計算機整體性能要求的提高,計算機系統性能的優化就顯得尤為重要。
一、計算機系統運行不佳的原因分析
計算機系統運行性能不佳的原因有很多。如,系統平臺結構不好、系統配置不好或參數設置不對;應用系統數據結構設計不合理,加大了系統的輸入和輸出需求;應用系統算法或邏輯處理有問題,使計算機系統達不到最佳的運行狀態。
二、計算機系統性能優化措施
1.合理地配置各種軟件,使計算機系統發揮最好的功能。計算機系統由硬件系統和軟件系統組成,二者之間相互依賴,這就要求我們在使用計算機軟件的過程中,使用一些速度較快、版本較高和功能較完善的軟件,并仔細閱讀各種軟件的使用說明,避免在應用過程中發生沖突。作為編程人員,在編寫應用程序的過程中,要充分考慮應用系統數據結構設計的合理性,以便使計算機系統達到最佳的運行狀態。
2.調整輸入和輸出系統。在計算機系統的應用過程中,我們進行的大多數操作就是輸入和輸出。因此,輸入和輸出操作是影響計算機性能的一個重要因素。隨著科技的日益發
展,磁盤的平均尋址時間日益縮短,但與中央處理器的運算相比,仍然緩慢很多。在觀察一些系統運行時,經常出現中央處理器處在空閑狀態而應用程序卻遲遲不能完成的情況。究其原因,就是因為磁盤的輸入和輸出的速度太慢,數據沒有讀(寫)入內存中。因此,在實際的應用過程中,我們可以考慮把數據文件存放在不同的磁盤上,讓多個磁盤并行工作,從而解決輸入和輸出的瓶頸問題。如果輸入和輸出總數明顯不合理,就要考慮查找引起輸入和輸出數量增大的原因,從而優化應用程序,減少輸入和輸出的次數,提高系統的性能。
3.安排相同性質的處理過程同時運行,以確保中央處理器和輸入和輸出的絕對通暢。一臺計算機能夠同時運行多個應用程序,從使用系統資源的角度來看,這些應用程序可以分為面向輸入和輸出與面向運算2種類型。
系統中如果有2個或多個面向輸入和輸出的應用在同時運行,就會造成中央處理器閑置而大量磁盤輸入和輸出擁塞和等待的情況,使得各個應用程序的性能變差。系統中如果有2個或多個面向運算的應用程序同時運行時,就會造成磁盤空轉的情況。因此,要盡量避免讓多個面向輸入和輸出或多個面向運算的應用程序同時運行。最好的安排就是讓面向輸入和輸出與面向運算的應用程序合理搭配,使每個應用都能獲得足夠的系統服務而又互不影響。
4.合理地使用中央處理器。一般來說,在一個計算機系統中,中央處理器的速度要遠遠高于輸入和輸出的速度,因而輸入和輸出速度往往是影響系統性能的主要因素。但必須指出的是,這種規則只適用于普通的情況。如果不知道中央處理器能力也有一定限制,盲目地、不合理地使用中央處理器,中央處理器也會成為影響系統性能的主要因素。
通過對計算機系統的性能進行優化,排除了系統中的各種不合理因素,縮短了系統的響應時間,使計算機系統能更好地發揮作用,從而為我們提供更好的服務。
第四篇:2013總結2012網站優化技巧
1、構架:保留原有框架、構架:
2、網頁設計:顏色要求合理,避免太大出入造成的眼睛疲勞。原網站的底圖案,是福字底,、網頁設計: 可以進行采納
3、增加:增加一個網站商城系統,用來方便用戶購物,并在首頁設置連接、增加:
4、網站導航優化、網站導航優化:將第二部關鍵詞分析得到的結果分別布置到相應導航欄,次導航欄以及 側欄等。并建立完善的網站地圖,方便用戶和搜索引擎蜘蛛。網站建設技術:
5、長尾關鍵詞。結合沃爾瑪,銀泰,世紀聯華網站參考情況最后篩選出合適 的二級關鍵詞布置到相應的欄目。更新繼續挖掘細分的長尾關鍵詞,按照用戶搜索習慣來劃分,項目名稱和長尾關鍵詞越貼近用戶搜索就越容易取名。
6、網站導航優化、網站導航優化:將第二部關鍵詞分析得到的結果分別布置到相應導航欄,次導航欄以及 側欄等。并建立完善的網站地圖,方便用戶和搜索引擎蜘蛛。
7、權重:網站內部權重控制,用robots.txt屏蔽js、css文件等無意義、不需要權重的頁 面。圖片優化:對圖片進行優化,上傳圖片的時候添加alt文本描述;部分圖片可以采取下 面用文字描述,加粗,包含關鍵字的優化方式。
8、其他相關設計: 添加相關css hack代碼,使網站能夠得到大部分瀏覽器的支持; 樣式代碼遵守W3C規范; 代碼編寫按Web2.0標準進行; 統一采用DIV結構+CSS代碼; css、js、flash、iframe優化。網站建設完畢后刪除程序中的注釋代碼、多余的空行以及冗余代碼。根據SEO的需要,隨時調整網站每個頁面的一些功能,如最新文章調用,深層次文章增一 些站內外的其他導入口。
9.site,domain,link 數據 數據。查看網站在搜索引薦的收錄數量。查看網站的外部 鏈接,百度用 domain 和 link,google 用 link.查看外鏈的數據是一個,二是查看是 從什么地方帶來的外鏈(也就是外鏈的質量如何)外鏈在 SEO 中是相當重要的。你需要分析網站的外鏈來自那里,還要分析外鏈在別的網站的位置等。
10.網頁標簽優化 網頁標簽優化 網頁 TITIEL 關鍵詞標簽、描述標簽,圖片注釋、FLASH 注釋等方面的優化 超連接結構、超鏈接注釋、超連接路徑優化 對主要頁面內容進行調整、排版進行優化,讓內容更容 3.超鏈接優化 超鏈接優化 4 頁面內容優化 易閱讀。5 站內細節優化 URL 靜態化及嵌入 首選域 Robots.txt 網站關鍵詞密度控制 2%-8%之間 404 頁面設置、301 重定向 內頁增加錨文本以及第一次出現該頁關鍵詞進行加粗 長尾關鍵詞記錄單 網站地圖 sitemap 網站快照及日志、數據分析 網站推廣(負責人:網站編輯、外鏈建設專員)
11.通過論壇,分類信息,博客,通過論壇,分類信息,博客,問答類網 百科,站,百科,行業網站等建設大量高質量 200 外鏈 尋找同行業網站建立長期鏈接關系,網站建立長期鏈接關系 購 尋找同行業網站建立長期鏈接關系,買高質量的友情鏈接提升網站權重。
文章由:傳奇萬能登陸器http:// 原創發布
第五篇:心得總結:Java性能優化技巧集錦
心得總結:Java性能優化技巧集錦
一、通用篇
“通用篇”討論的問題適合于大多數Java應用。
1.1 不用new關鍵詞創建類的實例
用new關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如果一個對象實現了Cloneable接口,我們可以調用它的clone()方法。clone()方法不會調用任何類構造函數。
在使用設計模式(Design Pattern)的場合,如果用Factory模式創建對象,則改用clone()方法創建新的對象實例非常簡單。例如,下面是Factory模式的一個典型實現: public static Credit getNewCredit(){ return new Credit();}
改進后的代碼使用clone()方法,如下所示: private static Credit BaseCredit = new Credit();public static Credit getNewCredit(){ return(Credit)BaseCredit.clone();}
上面的思路對于數組處理同樣很有用。
1.2 使用非阻塞I/O
版本較低的JDK不支持非阻塞I/O API。為避免I/O阻塞,一些應用采用了創建大量線程的辦法(在較好的情況下,會使用一個緩沖池)。這種技術可以在許多必須支持并發I/O流的應用中見到,如Web服務器、報價和拍賣應用等。然而,創建Java線程需要相當可觀的開銷。
JDK 1.4引入了非阻塞的I/O庫(java.nio)。如果應用要求使用版本較早的JDK,在這里有一個支持非阻塞I/O的軟件包。
請參見Sun中國網站的《調整Java的I/O性能》。
1.3 慎用異常
異常對性能不利。拋出異常首先要創建一個新的對象。Throwable接口的構造函數調用名為fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法檢查堆棧,收集調用跟蹤信息。只要有異常被拋出,VM就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。
異常只能用于錯誤處理,不應該用來控制程序流程。
1.4 不要重復初始化變量
默認情況下,調用類的構造函數時,Java會把變量初始化成確定的值:所有的對象被設置成null,整數變量(byte、short、int、long)設置成0,float和 double變量設置成0.0,邏輯值設置成false。當一個類從另一個類派生時,這一點尤其應該注意,因為用new關鍵詞創建一個對象時,構造函數鏈中的所有構造函數都會被自動調用。
1.5 盡量指定類的final修飾符
帶有final修飾符的類是不可派生的。在Java核心API中,有許多應用final的例子,例如java.lang.String。為String類指定final防止了人們覆蓋length()方法。
另外,如果指定一個類為final,則該類所有的方法都是final。Java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使性能平均提高50%。
1.6 盡量使用局部變量
調用方法時傳遞的參數以及在調用中創建的臨時變量都保存在棧(Stack)中,速度較快。其他變量,如靜態變量、實例變量等,都在堆(Heap)中創建,速度較慢。另外,依賴于具體的編譯器/JVM,局部變量還可能得到進一步優化。請參見《盡可能使用堆棧變量》。
1.7 乘法和除法
考慮下面的代碼:
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;}
修改后的代碼不再做乘以8的操作,而是改用等價的左移3位操作,每左移1位相當于乘以2。相應地,右移1位操作相當于除以2。值得一提的是,雖然移位操作速度快,但可能使代碼比較難于理解,所以最好加上一些注釋。
二、J2EE篇
前面介紹的改善性能技巧適合于大多數Java應用,接下來要討論的問題適合于使用JSP、EJB或JDBC的應用。
2.1 使用緩沖標記
一些應用服務器加入了面向JSP的緩沖標記功能。例如,BEA的WebLogic Server從6.0版本開始支持這個功能,Open Symphony工程也同樣支持這個功能。JSP緩沖標記既能夠緩沖頁面片斷,也能夠緩沖整個頁面。當JSP頁面執行時,如果目標片斷已經在緩沖之中,則生成該片斷的代碼就不用再執行。頁面級緩沖捕獲對指定URL的請求,并緩沖整個結果頁面。對于購物籃、目錄以及門戶網站的主頁來說,這個功能極其有用。對于這類應用,頁面級緩沖能夠保存頁面執行的結果,供后繼請求使用。
對于代碼邏輯復雜的頁面,利用緩沖標記提高性能的效果比較明顯;反之,效果可能略遜一籌。
請參見《用緩沖技術提高JSP應用的性能和穩定性》。
2.2 始終通過會話Bean訪問實體Bean
直接訪問實體Bean不利于性能。當客戶程序遠程訪問實體Bean時,每一個get方法都是一個遠程調用。訪問實體Bean的會話Bean是本地的,能夠把所有數據組織成一個結構,然后返回它的值。
用會話Bean封裝對實體Bean的訪問能夠改進事務管理,因為會話Bean只有在到達事務邊界時才會提交。每一個對get方法的直接調用產生一個事務,容器將在每一個實體Bean的事務之后執行一個“裝入-讀取”操作。
一些時候,使用實體Bean會導致程序性能不佳。如果實體Bean的唯一用途就是提取和更新數據,改成在會話Bean之內利用JDBC訪問數據庫可以得到更好的性能。
2.3 選擇合適的引用機制
在典型的JSP應用系統中,頁頭、頁腳部分往往被抽取出來,然后根據需要引入頁頭、頁腳。當前,在JSP頁面中引入外部資源的方法主要有兩種:include指令,以及include動作。
include指令:例如<%@ include file=“copyright.html” %>。該指令在編譯時引入指定的資源。在編譯之前,帶有include指令的頁面和指定的資源被合并成一個文件。被引用的外部資源在編譯時就確定,比運行時才確定資源更高效。
include動作:例如
2.4 在部署描述器中設置只讀屬性
實體Bean的部署描述器允許把所有get方法設置成“只讀”。當某個事務單元的工作只包含執行讀取操作的方法時,設置只讀屬性有利于提高性能,因為容器不必再執行存儲操作。
2.5 緩沖對EJB Home的訪問
EJB Home接口通過JNDI名稱查找獲得。這個操作需要相當可觀的開銷。JNDI查找最好放入Servlet的init()方法里面。如果應用中多處頻繁地出現EJB訪問,最好創建一個EJBHomeCache類。EJBHomeCache類一般應該作為singleton實現。
2.6 為EJB實現本地接口
本地接口是EJB 2.0規范新增的內容,它使得Bean能夠避免遠程調用的開銷。請考慮下面的代碼。PayBeanHome home =(PayBeanHome)javax.rmi.PortableRemoteObject.narrow(ctx.lookup(“PayBeanHome”), PayBeanHome.class);PayBean bean =(PayBean)javax.rmi.PortableRemoteObject.narrow(home.create(), PayBean.class);
第一個語句表示我們要尋找Bean的Home接口。這個查找通過JNDI進行,它是一個RMI調用。然后,我們定位遠程對象,返回代理引用,這也是一個 RMI調用。第二個語句示范了如何創建一個實例,涉及了創建IIOP請求并在網絡上傳輸請求的stub程序,它也是一個RMI調用。
要實現本地接口,我們必須作如下修改:
方法不能再拋出java.rmi.RemoteException異常,包括從RemoteException派生的異常,比如 TransactionRequiredException、TransactionRolledBackException和 NoSuchObjectException。EJB提供了等價的本地異常,如TransactionRequiredLocalException、TransactionRolledBackLocalException和NoSuchObjectLocalException。
所有數據和返回值都通過引用的方式傳遞,而不是傳遞值。
本地接口必須在EJB部署的機器上使用。簡而言之,客戶程序和提供服務的組件必須在同一個JVM上運行。
如果Bean實現了本地接口,則其引用不可串行化。
請參見《用本地引用提高EJB訪問效率》。
軟件資訊 > 開發特區 > 開發語言 > Java
2006年05月11日 作者:songxin 責任編輯:xietaoming
文章導讀:分通用篇、J2EE篇、GUI篇三部分介紹Java性能優化技巧。
2.7 生成主鍵
在EJB之內生成主鍵有許多途徑,下面分析了幾種常見的辦法以及它們的特點。
利用數據庫內建的標識機制(SQL Server的IDENTITY或Oracle的SEQUENCE)。這種方法的缺點是EJB可移植性差。
由實體Bean自己計算主鍵值(比如做增量操作)。它的缺點是要求事務可串行化,而且速度也較慢。
利用NTP之類的時鐘服務。這要求有面向特定平臺的本地代碼,從而把Bean固定到了特定的OS之上。另外,它還導致了這樣一種可能,即在多CPU的服務器上,同一個毫秒之內生成了兩個主鍵。
借鑒Microsoft的思路,在Bean中創建一個GUID。然而,如果不求助于JNI,Java不能確定網卡的MAC地址;如果使用JNI,則程序就要依賴于特定的OS。
還有其他幾種辦法,但這些辦法同樣都有各自的局限。似乎只有一個答案比較理想:結合運用RMI和JNDI。先通過RMI注冊把RMI遠程對象綁定到JNDI樹。客戶程序通過JNDI進行查找。下面是一個例子: public class keyGenerator extends UnicastRemoteObject implements Remote { private static long KeyValue = System.currentTimeMillis();public static synchronized long getKey()throws RemoteException { return KeyValue++;}
2.8 及時清除不再需要的會話
為了清除不再活動的會話,許多應用服務器都有默認的會話超時時間,一般為30分鐘。當應用服務器需要保存更多會話時,如果內存容量不足,操作系統會把部分內存數據轉移到磁盤,應用服務器也可能根據“最近最頻繁使用”(Most Recently Used)算法把部分不活躍的會話轉儲到磁盤,甚至可能拋出“內存不足”異常。在大規模系統中,串行化會話的代價是很昂貴的。當會話不再需要時,應當及時調用HttpSession.invalidate()方法清除會話。HttpSession.invalidate()方法通常可以在應用的退出頁面調用。
2.9 在JSP頁面中關閉無用的會話
對于那些無需跟蹤會話狀態的頁面,關閉自動創建的會話可以節省一些資源。使用如下page指令: <%@ page session=“false”%>
2.10 Servlet與內存使用
許多開發者隨意地把大量信息保存到用戶會話之中。一些時候,保存在會話中的對象沒有及時地被垃圾回收機制回收。從性能上看,典型的癥狀是用戶感到系統周期性地變慢,卻又不能把原因歸于任何一個具體的組件。如果監視JVM的堆空間,它的表現是內存占用不正常地大起大落。
解決這類內存問題主要有二種辦法。第一種辦法是,在所有作用范圍為會話的Bean中實現HttpSessionBindingListener接口。這樣,只要實現valueUnbound()方法,就可以顯式地釋放Bean使用的資源。
另外一種辦法就是盡快地把會話作廢。大多數應用服務器都有設置會話作廢間隔時間的選項。另外,也可以用編程的方式調用會話的 setMaxInactiveInterval()方法,該方法用來設定在作廢會話之前,Servlet容器允許的客戶請求的最大間隔時間,以秒計。
2.11 HTTP Keep-Alive
Keep-Alive功能使客戶端到服務器端的連接持續有效,當出現對服務器的后繼請求時,Keep-Alive功能避免了建立或者重新建立連接。市場上的大部分Web服務器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。對于提供靜態內容的網站來說,這個功能通常很有用。但是,對于負擔較重的網站來說,這
里存在另外一個問題:雖然為客戶保留打開的連接有一定的好處,但它同樣影響了性能,因為在處理暫停期間,本來可以釋放的資源仍舊被占用。當Web服務器和應用服務器在同一臺機器上運行時,Keep-Alive功能對資源利用的影響尤其突出。
2.12 JDBC與Unicode
想必你已經了解一些使用JDBC時提高性能的措施,比如利用連接池、正確地選擇存儲過程和直接執行的SQL、從結果集刪除多余的列、預先編譯SQL語句,等等。
除了這些顯而易見的選擇之外,另一個提高性能的好選擇可能就是把所有的字符數據都保存為Unicode(代碼頁13488)。Java以Unicode形式處理所有數據,因此,數據庫驅動程序不必再執行轉換過程。但應該記住:如果采用這種方式,數據庫會變得更大,因為每個Unicode字符需要2個字節存儲空間。另外,如果有其他非Unicode的程序訪問數據庫,性能問題仍舊會出現,因為這時數據庫驅動程序仍舊必須執行轉換過程。
2.13 JDBC與I/O
如果應用程序需要訪問一個規模很大的數據集,則應當考慮使用塊提取方式。默認情況下,JDBC每次提取32行數據。舉例來說,假設我們要遍歷一個5000 行的記錄集,JDBC必須調用數據庫157次才能提取到全部數據。如果把塊大小改成512,則調用數據庫的次數將減少到10次。
在一些情形下這種技術無效。例如,如果使用可滾動的記錄集,或者在查詢中指定了FOR UPDATE,則塊操作方式不再有效。
2.14 內存數據庫
許多應用需要以用戶為單位在會話對象中保存相當數量的數據,典型的應用如購物籃和目錄等。由于這類數據可以按照行/列的形式組織,因此,許多應用創建了龐大的Vector或HashMap。在會話中保存這類數據極大地限制了應用的可伸縮性,因為服務器擁有的內存至少必須達到每個會話占用的內存數量乘以并發用戶最大數量,它不僅使服務器價格昂貴,而且垃圾收集的時間間隔也可能延長到難以忍受的程度。
一些人把購物籃/目錄功能轉移到數據庫層,在一定程度上提高了可伸縮性。然而,把這部分功能放到數據庫層也存在問題,且問題的根源與大多數關系數據庫系統的體系結構有關。對于關系數據庫來說,運行時的重要原則之一是確保所有的寫入操作穩定、可靠,因而,所有的性能問題都與物理上把數據寫入磁盤的能力有關。關系數據庫力圖減少I/O操作,特別是對于讀操作,但實現該目標的主要途徑只是執行一套實現緩沖機制的復雜算法,而這正是數據庫層第一號性能瓶頸通常總是 CPU的主要原因。
一種替代傳統關系數據庫的方案是,使用在內存中運行的數據庫(In-memory Database),例如TimesTen。內存數據庫的出發點是允許數據臨時地寫入,但這些數據不必永久地保存到磁盤上,所有的操作都在內存中進行。這樣,內存數據庫不需要復雜的算法來減少I/O操作,而且可以采用比較簡單的加鎖機制,因而速度很快。
三、GUI篇
這一部分介紹的內容適合于圖形用戶界面的應用(Applet和普通應用),要用到AWT或Swing。
3.1 用JAR壓縮類文件
Java檔案文件(JAR文件)是根據JavaBean標準壓縮的文件,是發布JavaBean組件的主要方式和推薦方式。JAR檔案有助于減少文件體積,縮短下載時間。例如,它有助于Applet提高啟動速度。一個JAR文件可以包含一個或者多個相關的Bean以及支持文件,比如圖形、聲音、HTML 和其他資源。
要在HTML/JSP文件中指定JAR文件,只需在Applet標記中加入ARCHIVE = “name.jar”聲明。
請參見《使用檔案文件提高 applet 的加載速度》。
3.2 提示Applet裝入進程
你是否看到過使用Applet的網站,注意到在應該運行Applet的地方出現了一個占位符?當Applet的下載時間較長時,會發生什么事情?最大的可能就是用戶掉頭離去。在這種情況下,顯示一個Applet正在下載的信息無疑有助于鼓勵用戶繼續等待。
下面我們來看看一種具體的實現方法。首先創建一個很小的Applet,該Applet負責在后臺下載正式的Applet:
import java.applet.Applet;import java.applet.AppletStub;import java.awt.Label;import java.awt.Graphics;import java.awt.GridLayout;public class PreLoader extends Applet implements Runnable, AppletStub { String largeAppletName;Label label;public void init(){ // 要求裝載的正式Applet largeAppletName = getParameter(“applet”);// “請稍等”提示信息
label = new Label(“請稍等...” + largeAppletName);add(label);} public void run(){ try { // 獲得待裝載Applet的類
Class largeAppletClass = Class.forName(largeAppletName);// 創建待裝載Applet的實例
Applet largeApplet =(Applet)largeAppletClass.newInstance();// 設置該Applet的Stub程序 largeApplet.setStub(this);// 取消“請稍等”信息 remove(label);// 設置布局
setLayout(new GridLayout(1, 0));add(largeApplet);// 顯示正式的Applet largeApplet.init();largeApplet.start();} catch(Exception ex){ // 顯示錯誤信息
label.setText(“不能裝入指定的Applet”);} // 刷新屏幕 validate();
} public void appletResize(int width, int height){ // 把appletResize調用從stub程序傳遞到Applet resize(width, height);} }
編譯后的代碼小于2K,下載速度很快。代碼中有幾個地方值得注意。首先,PreLoader實現了AppletStub接口。一般地,Applet從調用者判斷自己的codebase。在本例中,我們必須調用setStub()告訴Applet到哪里提取這個信息。另一個值得注意的地方是,AppletStub接口包含許多和Applet類一樣的方法,但appletResize()方法除外。這里我們把對appletResize()方法的調用傳遞給了resize()方法。
3.3 在畫出圖形之前預先裝入它
ImageObserver接口可用來接收圖形裝入的提示信息。ImageObserver接口只有一個方法imageUpdate(),能夠用一次repaint()操作在屏幕上畫出圖形。下面提供了一個例子。public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h){ if((flags & ALLBITS)!=0 { repaint();} else if(flags &(ERROR |ABORT))!= 0){ error = true;// 文件沒有找到,考慮顯示一個占位符 repaint();} return(flags &(ALLBITS | ERROR| ABORT))== 0;}
當圖形信息可用時,imageUpdate()方法被調用。如果需要進一步更新,該方法返回true;如果所需信息已經得到,該方法返回false。
3.4 覆蓋update方法
update()方法的默認動作是清除屏幕,然后調用paint()方法。如果使用默認的update()方法,頻繁使用圖形的應用可能出現顯示閃爍現象。要避免在paint()調用之前的屏幕清除操作,只需按照如下方式覆蓋update()方法:
public void update(Graphics g){ paint(g);}
更理想的方案是:覆蓋update(),只重畫屏幕上發生變化的區域,如下所示: public void update(Graphics g){ g.clipRect(x, y, w, h);paint(g);}
3.5 延遲重畫操作
對于圖形用戶界面的應用來說,性能低下的主要原因往往可以歸結為重畫屏幕的效率低下。當用戶改變窗口大小或者滾動一個窗口時,這一點通常可以很明顯地觀察到。改變窗口大小或者滾動屏幕之類的操作導致重畫屏幕事件大量地、快速地生成,甚至超過了相關代碼的執行速度。對付這個問題最好的辦法是忽略所有“遲到” 的事件。
建議在這里引入一個數毫秒的時差,即如果我們立即接收到了另一個重畫事件,可以停止處理當前事件轉而處理最后一個收到的重畫事件;否則,我們繼續進行當前的重畫過程。
如果事件要啟動一項耗時的工作,分離出一個工作線程是一種較好的處理方式;否則,一些部件可能被“凍結”,因為每次只能處理一個事件。下面提供了一個事件處理的簡單例子,但經過擴展后它可以用來控制工作線程。
public static void runOnce(String id, final long milliseconds){ synchronized(e_queue){ // e_queue: 所有事件的集合 if(!e_queue.containsKey(id)){ e_queue.put(token, new LastOne());} } final LastOne lastOne =(LastOne)e_queue.get(token);final long time = System.currentTimeMillis();// 獲得當前時間 lastOne.time = time;(new Thread(){public void run(){ if(milliseconds > 0){ try {Thread.sleep(milliseconds);} // 暫停線程 catch(Exception ex){} } synchronized(lastOne.running){ // 等待上一事件結束 if(lastOne.time!= time)// 只處理最后一個事件 return;} }}).start();} private static Hashtable e_queue = new Hashtable();private static class LastOne { public long time=0;public Object running = new Object();}
3.6 使用雙緩沖區
在屏幕之外的緩沖區繪圖,完成后立即把整個圖形顯示出來。由于有兩個緩沖區,所以程序可以來回切換。這樣,我們可以用一個低優先級的線程負責畫圖,使得程序能夠利用空閑的CPU時間執行其他任務。下面的偽代碼片斷示范了這種技術。Graphics myGraphics;Image myOffscreenImage = createImage(size().width, size().height);
Graphics offscreenGraphics = myOffscreenImage.getGraphics();offscreenGraphics.drawImage(img, 50, 50, this);myGraphics.drawImage(myOffscreenImage, 0, 0, this);
3.7 使用BufferedImage
Java JDK 1.2使用了一個軟顯示設備,使得文本在不同的平臺上看起來相似。為實現這個功能,Java必須直接處理構成文字的像素。由于這種技術要在內存中大量地進行位復制操作,早期的JDK在使用這種技術時性能不佳。為解決這個問題而提出的Java標準實現了一種新的圖形類型,即BufferedImage。
BufferedImage子類描述的圖形帶有一個可訪問的圖形數據緩沖區。一個BufferedImage包含一個ColorModel和一組光柵圖形數據。這個類一般使用RGB(紅、綠、藍)顏色模型,但也可以處理灰度級圖形。它的構造函數很簡單,如下所示:
public BufferedImage(int width, int height, int imageType)
ImageType允許我們指定要緩沖的是什么類型的圖形,比如5-位RGB、8-位RGB、灰度級等。
3.8 使用VolatileImage
許多硬件平臺和它們的操作系統都提供基本的硬件加速支持。例如,硬件加速一般提供矩形填充功能,和利用CPU完成同一任務相比,硬件加速的效率更高。由于硬件加速分離了一部分工作,允許多個工作流并發進行,從而緩解了對CPU和系統總線的壓力,使得應用能夠運行得更快。利用VolatileImage可以創建硬件加速的圖形以及管理圖形的內容。由于它直接利用低層平臺的能力,性能的改善程度主要取決于系統使用的圖形適配器。VolatileImage的內容隨時可能丟失,也即它是“不穩定的(volatile)”。因此,在使用圖形之前,最好檢查一下它的內容是否丟失。VolatileImage有兩個能夠檢查內容是否丟失的方法: public abstract int validate(GraphicsConfiguration gc);public abstract Boolean contentsLost();
每次從VolatileImage對象復制內容或者寫入VolatileImage時,應該調用validate()方法。contentsLost()方法告訴我們,自從最后一次validate()調用之后,圖形的內容是否丟失。
雖然VolatileImage是一個抽象類,但不要從它這里派生子類。VolatileImage應該通過
Component.createVolatileImage()或者 GraphicsConfiguration.createCompatibleVolatileImage()方法創建。
3.9 使用Window Blitting
進行滾動操作時,所有可見的內容一般都要重畫,從而導致大量不必要的重畫工作。許多操作系統的圖形子系統,包括WIN32 GDI、MacOS和X/Windows,都支持Window Blitting技術。Window Blitting技術直接在屏幕緩沖區中把圖形移到新的位置,只重畫新出現的區域。要在Swing應用中使用Window Blitting技術,設置方法如下: setScrollMode(int mode);
在大多數應用中,使用這種技術能夠提高滾動速度。只有在一種情形下,Window Blitting會導致性能降低,即應用在后臺進行滾動操作。如果是用戶在滾動一個應用,那么它總是在前臺,無需擔心任何負面影響。