qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          如何用好LoadRunner中的檢查點

          如何用好LoadRunner中的檢查點
          轉自:領測軟件測試網[http://www.ltesting.net]
          原文鏈接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946.html

          如何用好LoadRunner中的檢查點LR中檢查點有兩種:圖片和文字。 常用檢查點函數如下: 1)web_find()函數用于從 HTML 頁中搜索指定的文本字符串; 2)web_reg_find()函數注冊一個請求,以在下一個操作函數(如 web_url)檢索到的HTML網頁上搜  LR中檢查點有兩種:圖片和文字。

            常用檢查點函數如下:

           

            1)web_find()函數用于從 HTML 頁中搜索指定的文本字符串;

            2)web_reg_find()函數注冊一個請求,以在下一個操作函數(如 web_url)檢索到的HTML網頁上搜索指定的文本字符串;

            3)web_image_check()函數用于從HTML頁面中查找指定的圖片;

            4)web_global_verfication()屬于注冊函數,注冊一個在web頁面中搜索文本字符串的請求,與web_reg_find只在下一個Action函數中執行搜索不同的是它在之后所有的Action類函數中執行搜索指定的文本字符串;


            下面分別介紹以上函數的用法:

            1、web_find()函數參數舉例:


            web_find("web_find","RighOf=a","LeftOf=b","What=name",LAST);

           

            參數解釋:"web_find"定義該查找函數的名稱;“LeftOf”和“RighOf=”用來定義查找字符的左右邊界;“What=”定義查找內容;

            例如上述參數舉例中的意思就是在頁面中查找左邊界為b,右邊界為a,內容為name的信息;


            使用該函數注意事項:該函數是在查找頁面中的內容,所以要放在要查找的內容的后面;該函數只能在基于HTML模式錄制的腳本中進行查找

            注意事項:使用該函數時,要在Vuser->Run-Tme Settings中更改下設置


            勾選Enable Image and text check

           

            系統默認是不勾選該選項的。

           

            2、web_reg_find()函數參數舉例:


            web_reg_find("Search=Body","SaveCount=ddd","Test=aaa",LAST);

            參數解釋: Search用來定義查找范圍,SaveCount定義查找計數變量名稱,該參數可以記錄在緩存中查找內容出現的次數,可以使用該值,來判斷要查找的內容是否被找到;

           

            例如上述參數舉例中的意思就是Body中查找內容為aaa的信息,并將出現次數記錄在變量ddd中;

            【代碼一:web_reg_find("Text=Payment Details",LAST);

           

            代碼思路:1.“Payment Details” 為你要檢查的文本;

            2. 腳本執行到此處,若在頁面上找到了這幾個字符串,那腳本繼續執行下去;若沒有找到,腳本將在此報錯并且結束。】

            【代碼二:web_reg_find("Text=Payment Details", "SaveCount=para_count", LAST); //check 的函數

            web_submit_form("reservations.pl_2", //要check的頁面的錄制時的代碼

            "Snapshot=t22.inf",


            ITEMDATA,

            "Name=outboundFlight", "Value=003;0;06/23/2007", ENDITEM,

            "Name=reserveFlights.x", "Value=61", ENDITEM,


            "Name=reserveFlights.y", "Value=2", ENDITEM,

            LAST);

           

            if (atoi(lr_eval_string("{para_count}"))>0) //驗證是否找到了頁面上的要檢查的字符串

            lr_output_message("we find the string!");

            else

           

            lr_output_message("sorry,don't find the string!");

            代碼思路:1.“Payment Details” 為你要檢查的文本;

            2. 腳本執行到此處,不管頁面上是否存在你要檢查的字符串,腳本都不會報錯,而是執行下去。

            3. 此段代碼將找到的你要檢查的字符串的個數,存為一個參數。 然后在頁面代碼的后面,通過檢查這個參數的值是否大于0,來判斷是否找到了你所要檢查的字符串。】

            【代碼三:


            A. web_reg_find("Text=Payment Detdils", "Fail=NotFound",LAST);或

            B. web_reg_find("Text=Payment Detdils", "Fail=Found",LAST);


            代碼思路:


            1.“Payment Details” 為你要檢查的文本;


            2. 若是A代碼:腳本執行到此處,若沒有找到check的字符串,腳本將FAIL, 并且停止執行下去。反之,則一直執行下去。

            3. 若是B代碼:腳本執行到此處,若找到check的字符串,腳本將FAIL, 并且停止執行下去。反之,則一直執行下去】

           

            使用該函數注意事項:該函數是在緩存中查找相應的內容,所以要放在查找內容之前;通常情況下寫在如下六個函數之前:Web_castom_request(); web_image(); web_link(); web_submit_data(); web_submit_form(); web_url();

            使用技巧:在該函數的參數中有個“SaveCount”,該參數可以記錄在緩存中查找內容出現的次數,我們可以使用該值,來判斷要查找的內容是否被找到,下面舉個例子來說明:(引用LR的幫助中的例子)


            // Run the Web Tours sample

           

            web_url("MercuryWebTours",

            "URL=http://localhost/MercuryWebTours/",

            "Resource=0",

           

            "RecContentType=text/html",

            "Referer=",

           

            "Snapshot=t1.inf",

           

            "Mode=HTML",

           

            LAST);

           

            // Set up check for successful login by looking for "Welcome"

            web_reg_find("Text=Welcome",

            "SaveCount=Welcome_Count",


            LAST);

            // Now log in

            web_submit_form("login.pl",

            "Snapshot=t2.inf",

          轉自:領測軟件測試網[http://www.ltesting.net]


          ITEMDATA, Name=username, Value=jojo, ENDITEM, Name=password, Value=bean, ENDITEM, Name=login.x, Value=35, ENDITEM, Name=login.y, Value=14, ENDITEM, LAST); // Check result if (atoi(lr_eval_string({Wel
            ITEMDATA,

            "Name=username", "Value=jojo", ENDITEM,

            Name=password", "Value=bean", ENDITEM,

            "Name=login.x", "Value=35", ENDITEM,

           

            "Name=login.y", "Value=14", ENDITEM,


            LAST);


            // Check result

            if (atoi(lr_eval_string("{Welcome_Count}")) > 0){ //判斷如果Welcome字符串出現次數大于0


            lr_output_message("Log on successful."); }//在日志中輸出Log on successful

            else{ //如果出現次數小于等于

            lr_error_message("Log on failed"); //在日志中輸出Log on failed


            return(0); }


            我覺得這個方法非常有用,我們可以舉一反三,應用到我們實際的項目

            注:在錄制過程中添加的檢查點,用到的函數是web_reg_find(),且參數只有“Text=”

            3、web_image_check()函數參數說明:

            web_image_check("web_image_check","Alt=","Src=",LAST);

           

            參數解釋:“Alt”和“Src”的值直接取該圖片在網頁源代碼中相應參數的值;

           

            注意事項:使用該函數時,要在Vuser->Run-Tme Settings中勾選Enable Image and text check,具體操作請看web_find()中的注意事項。


            經過測試,該函數用到查找內容前面或后面,都不影響查找結果。

           

            舉例說明(腳本)

            該腳本記錄的是登陸系統后退出的操作,在腳本中用到atoi()函數和lr_eval_string(”{SaveCount定義的變量}”)兩個函數結合使用,判斷查找內容出現的次數是否大于0,若大于0,則輸入登錄成功的信息。

           

            vuser_init()


            {

            web_url("xjcost",


            "URL=http://gczj-server8:9205/xjcost/",

           

            "Resource=0",

            "RecContentType=text/html",


            "Referer=",

            "Snapshot=t1.inf",


            "Mode=HTML",

           

            EXTRARES,


            "Url=jsp/images/index/index.swf", ENDITEM,

           

            "Url=jsp/images/index/xxfb2.gif", ENDITEM,

           

            "Url=jsp/images/index/ywpt2.gif", ENDITEM,

           

            LAST);

           

            web_url("userAction.struts",

           

            "URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",


            "Resource=0",

            "RecContentType=text/html",

           

            "Referer=",

            "Snapshot=t2.inf",

            "Mode=HTML",


            LAST);

            return 0;

            }

            Action()

           

            {

            lr_start_transaction("Log_on");


            lr_rendezvous("Log_on");

           

            web_add_cookie("userAccount=admin; DOMAIN=gczj-server8");

           

            web_reg_find("Text=歡迎您",

            "SaveCount=歡迎您_Count",


            LAST);

           

            web_image_check("web_image_check",

            "Src=/xjcost/jsp/images/index1/edit_01.gif",

            LAST);

           

            web_submit_data("userLogin.struts",

            "Action=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin",


            "Method=POST",

            "RecContentType=text/html",

            "Referer=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",

           

            "Snapshot=t3.inf",

            "Mode=HTML",

           

            ITEMDATA,

            "Name=userAccount", "Value=admin", ENDITEM,

            "Name=pwd", "Value=1111", ENDITEM,


            EXTRARES,

            "Url=jsp/images/index1/edit_01a.gif", "Referer=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin", ENDITEM,

            LAST);


            web_find("web_find",

            "What=歡迎您",

            LAST);

           

            lr_end_transaction("Log_on",LR_AUTO);

            //檢查是否登錄成功


            //如果“歡迎您”這個字符出現次數大于0,輸出“Log on successfully!”

            if(atoi(lr_eval_string("{歡迎您_Count}"))>0)


            lr_output_message("Log on successfully!");


            else

            lr_error_message("Log on failed!");


            return 0;

           

            return 0;

            }

            //atoi()函數的作用是將一個ASCII字符串轉換為整型

            //lr_eval_string()函數作用是取得參數值,將字符串變量中的參數值替換為當前的參數值并將這個字符串返回

           

            vuser_end()


            {

            lr_think_time(4);

           

            web_url("userAction.struts_2",


            "URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",

           

            "Resource=0",


            "RecContentType=text/html",

           

            "Referer=",


          轉自:領測軟件測試網[http://www.ltesting.net]
          原文鏈接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946_2.html

           

          Snapshot=t4.inf, Mode=HTML, LAST); return 0; } Global.h: #ifndef _GLOBALS_H #define _GLOBALS_H //-------------------------------------------------------------------- // Include Files #include lrun.h
            "Snapshot=t4.inf",

            "Mode=HTML",

            LAST);

           

            return 0;

           

            }

           

            Global.h:


            #ifndef _GLOBALS_H

            #define _GLOBALS_H

            //--------------------------------------------------------------------

            // Include Files

           

            #include "lrun.h"

           

            #include "web_api.h"

            #include "lrw_custom_body.h"

            //--------------------------------------------------------------------

            // Global Variables

           

            #endif // _GLOBALS_H


            Replay Log常見信息說明

           

            1、web_find()和web_image_check()函數的日志信息(這兩個日志信息實際上是一樣的,只是輸出的函數名和參數不同)

           

            1)信息1Action.c(22): Verification checks not enabled. web_image_check is skipped. See the 'Run-time settings/Preferences/Checks'


            [MsgId: MMSG-27197]

           

            Action.c(22): web_image_check was successful


            [MsgId: MMSG-26392]


            出現該信息,說明沒有勾選Enable Image and text check

           

            2)信息2Action.c(22): "web_image_check" succeeded (1 occurrence(s) found. Alt="", Src="/xjcost/jsp/images/index1/edit_01.gif")

            [MsgId: MMSG-27192]


            Action.c(22): web_image_check was successful

           

            [MsgId: MMSG-26392]

           

            出現該信息,說明檢查點設置成功,且已經查找到信息

            3)信息3Action.c(22): Error -27191: "web_image_check" failed (0 occurrence(s) found. Alt="", Src="/xjcost/jsp/images/index1/edit_1.gif")

            [MsgId: MERR-27191]


            Action.c(22): web_image_check highest severity level was "ERROR"

           

            [MsgId: MMSG-26391]

            出現該信息,說明要查找的內容沒有找到。這時依次嘗試以下操作:

           

            (1)檢查參數的信息是否寫錯;

            (2)如果是web_find(),檢查函數的位置是否在要查找內容的后面;

           

            (3)如果是web_image_check(),查看該圖片的源代碼,看其是否是這個頁面上的圖片,很可能是圖片選擇錯誤,即所選圖片不屬于該頁面。


            2、web_reg_find()函數的日志信息


            1)信息1Action.c(15): Registering web_reg_find was successful

           

            [MsgId: MMSG-26390]

            出現該信息,說明內容已查找到


            2)信息2Action.c(27): Error -26366: "Text=ABC" not found for web_reg_find

            [MsgId: MERR-26366]

           

            Action.c(27): web_submit_data("userLogin.struts") highest severity level was "ERROR", 18364 body bytes, 918 header bytes, 13 chunking overhead bytes

            [MsgId: MMSG-26387]

           

            該信息在replay log頁面是紅色顯示的,說明沒有找到內容,出現此情況嘗試以下兩個操作:

            (1)參數的信息是否正確;

           

            (2)查看該函數是否在查找內容的前面。


            插入函數的方法:

            1、 手工寫入,在需要插入函數的位置手工寫入該函數;

           

            2、 光標停留在要插入函數的位置,在INSERT菜單中,選擇new step,在列表中選擇或查找要插入的函數,根據提示填寫必要的參數;


            3、 在tree view模式下,在樹狀菜單中選中要插入函數的位置,右鍵,選擇insert after或insert before,根據提示填寫必要的參數;

            總結:


            1、 這兩個函數函數類型不同,WEB_FIND是普通函數,WEB_REG_FIND是注冊函數;

            2、 WEB_FIND使用時必須開啟內容檢查選項,而WEB_REG_FIND則不沒有此限制;

           

            3、 WEB_FIND只能用在基于HTML模式錄制的腳本中,而WEB_REG_FIND沒有此限制;


            4、 WEB_FIND是在返回的頁面中進行內容查找,WEB_REG_FIND是在緩存中進行查找;

            5、 WEB_FIND在執行效率上不如WEB_REG_FIND;


          轉自:領測軟件測試網[http://www.ltesting.net]
          原文鏈接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946_3.html


          原文鏈接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946.html

          posted @ 2012-01-25 22:18 順其自然EVO 閱讀(2737) | 評論 (0)編輯 收藏

          Linux系統下完成Windows的開發環境替換

           當下有很多的人都在Windows下進行開發工作,在Windows下搭建相關的開發環境并且使用各種開發工具進行工作。其實更多的專業開發人員會選擇Linux操作系統作為他們大的系統環境。理由很簡單,Linux運行起來更快,更靈活,更加安全。

            Windows下的開發環境以及軟件

            Visual Studio 2010

            Visual Studio 是微軟公司推出的開發環境。是目前最流行的 Windows 平臺應用程序開發環境。Visual Studio 可以用來創建 Windows 平臺下的 Windows 應用程序和網絡應用程序,也可以用來創建網絡服務、智能設備應用程序和 Office 插件。

            在VisualStudio2010中,微軟用全新的WPF技術重新打造了它的編輯器,借助WPF的強大功能,新的編輯器可以實現很多以前VisualStudio2008的IDE根本無法想象的功能,比如代碼的無級縮放,多窗口即時更新,文檔地圖,代碼的自動產生等等,這些新的IDE特性都會極大地提高程序員的開發效率。

            Linux系統下的開發環境架設與工具

            Eclipse,GCC,make,Perl,Python,Tcl/Tk各種語言都有。我的機器里安裝了Eclipse3.2及GCC等。在Linux下的java開發一點問題都沒有。tomcat、myeclipse、svn等一系例軟件都有Linux版本,很是方便。

            Tomcat

            Tomcat服務器是一個免費的開放源代碼的Web應用服務器,Tomcat很受廣大程序員的喜歡,因為它運行時占用的系統資源小,擴展性好,支持負載平衡與郵件服務等開發應用系統常用的功能;而且它還在不斷的改進和完善中,任何一個感興趣的程序員都可以更改它或在其中加入新的功能。

            大多數商業化的J2EE服務器都提供一個功能強大的管理界面,且大都采用易于理解的Web應用界面。Tomcat按照自己的方式,同樣提供一個成熟的管理工具,并且絲毫不遜于那些商業化的競爭對手。Tomcat的Admin Web Application最初在4.1版本時出現,當時的功能包括管理context、data source、user和group等。

          SVN

            SVN用戶管理系統是一套基于PHP+MYSQL運行環境的web程序,由Maia支持、Xuejiang開發,版權歸Maia和Xuejiang所有。程序的設計目的主要是幫助配置管理員方便、高效地管理Subversion系統(基于apache)的用戶及權限;至于配置庫創建、目錄創建、復制等配置庫操作則暫不在本程序考慮范圍內,因為這些操作Subversion本身已可高效完成,實無須再由第三方程序來畫蛇添足。

            Eclipse

            Eclipse 能夠更好的自動完成提示信息,對于關聯文件和路徑的設置可以使程序員在編碼過程中獲得整個項目的清晰視圖和方向指引。改進的文件鏈接功能可以更直接 的控制和管理項目中的文件和文件夾;管理Linux/Unix文件的權限屬性。

            據統計,太陽神所有項目的代碼有3300萬行之多,由來自44家公司的大約500名Eclipse.org社區自愿者貢獻的,需要注意的是,雖然這39個項目是統一時間發布,但并不意味著它們是統一的,每個項目都是Eclipse.org的獨立開源項目,它們都有自己的項目負責人,貢獻者和開發計劃,同期發布的目的是為了給大家提供一個可預見的開發周期。

            其實對于開發者來說,Linux系統環境更適合工作。上面介紹的Linux環境下開發工具與開發環境希望對大家會有所借鑒。




          posted @ 2012-01-20 09:59 順其自然EVO 閱讀(308) | 評論 (0)編輯 收藏

          分析TOP語句放到表值函數外,效率異常低下的原因

           SQLSERVER的表值函數是SQLSERVER 2005以來的新特性,由于它使用比較方便,就像一個單獨的表一樣,在我們的系統中大量使用。有一個獲取客戶數據的SQLSERVER 表值函數,如果使用管理員登錄,這個函數會返回150W行記錄,大概需要30秒左右,但如果將TOP語句放到表值函數外,效率異常低下,需要約3分鐘:

          select top 20  * from GetFrame_CustomerSerch('admin','1')

            下面是該存儲過程的定義:

          1. ALTER FUNCTION [dbo].[GetFrame_CustomerSerch]  
          2. (      
          3.     -- Add the parameters for the function here 
          4.     @WorkNo varchar(38)  
          5.     ,@SerchChar varchar(500)  
          6. )  
          7. RETURNS TABLE   
          8. AS 
          9. RETURN   
          10. (  
          11.     -- Add the SELECT statement with parameter references here 
          12.     select a.GUID,a.CustomerName,a.CustomerIDcard,a.CustomerPhone,a.CustomerMobile from 
          13.     (  
          14.    --具體子查詢略 
          15.     )  
          16.     ) a union all 
          17.     select b.GUID,b.CustomerName,b.CustomerIDcard,b.CustomerPhone,b.CustomerMobile from WFT_ManagerCollectUsers a left join WFT_Customer b on a.FundAccount=b.FundAccount  
          18.     --where a.WorkNo=@WorkNo 
          19.     WHERE a.WorkNo IN 
          20.     (  
          21. --具體子查詢略 
          22.     )  
          23.     )

            這個語句放在PDF.NET數據開發框架的SQL-MAP文件中,開始還以為是框架引起的,將這個語句直接在查詢分析器中查詢,仍然很慢。

            將GetFrame_CustomerSerch 中的SQL語句提取出來,直接加上Top查詢,只需要6秒,快了N倍:

          1. declare @WorkNo varchar(38)  
          2. declare @SerchChar varchar(500)  
          3. set @WorkNo='admin' 
          4. set @SerchChar='1' 
          5. select top 20 a.GUID,a.CustomerName,a.CustomerIDcard,a.CustomerPhone,a.CustomerMobile from 
          6.  (  
          7.   --具體子查詢略 
          8.  )  
          9.  ) a union all 
          10.  select b.GUID,b.CustomerName,b.CustomerIDcard,b.CustomerPhone,b.CustomerMobile from WFT_ManagerCollectUsers a left join WFT_Customer b on a.FundAccount=b.FundAccount  
          11.    
          12.  WHERE a.WorkNo IN 
          13.  (  
          14.  --具體子查詢略 
          15.  )

            為什么會有這么大的差異?

            我分析可能有如下原因:

            1、在表值函數外使用Top或者其它條件,SQLSERVER 的查詢優化器無法針對此查詢進行優化,比如先返回所有記錄,然后再在臨時表中選取前面的20條記錄;

            2、雖說該表值函數使用了“表變量”,它是內存中的,但如果這個“表”結果很大,很有可能內存放不下(并非還有物理內存就會將結果放到物理內存中,數據庫自己還會有保留的,會給其它查詢預留一定的內存空間),使用虛擬內存,而虛擬內存實際上就是磁盤頁面文件,當記錄太多就會發生頻繁的頁面交換,從而導致這個查詢效率非常低。

            看來,“表值函數”也不是傳說中的那么好,不知道大家是怎么認為的。

            最近還遇到一個怪異的問題,有一個存儲過程,老是在系統運行1-2天后變得極其緩慢,但重新修改一下又很快了(只是加一個空格之類),不知道大家遇到過沒有,什么原因?

          posted @ 2012-01-20 09:58 順其自然EVO 閱讀(354) | 評論 (1)編輯 收藏

          Swing使用Substance外觀包異常問題

               摘要: 問題一:今天更新我的Java版QQ,在網上找到了Substance外觀包,效果不錯,直接用了,可是設置水印問題時就出現問題,網上有現成的例子JFrame.setDefaultLookAndFeelDecorated(true);  JDialog.setDefaultLookAndFeelDecorated(true);  try  {  &nbs...  閱讀全文

          posted @ 2012-01-20 09:56 順其自然EVO 閱讀(547) | 評論 (0)編輯 收藏

          深入研究Java虛擬機的類加載機制

            說到Java虛擬機的類加載機制,很多朋友第一反應想到的應該就是ClassLoader,我也如此,不過ClassLoader其實只是Java虛擬機加載機制中的一部分,最近在看《深入理解Java虛擬機》,對Java虛擬機的類加載機制有了更深入的了解,不吐不快。

            JVM中類的整個生命周期如下:

            加載=》驗證=》準備=》解析=》初始化=》使用=》卸載

            使用和卸載這兩個步驟不在今天的討論范圍之內,今天我們將著重討論一下前5個步驟,也就是JVM中類的整個加載機制。

            1、加載

            類的加載階段,主要是獲取定義此類的二進制字節流,并將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構,最后在Java堆中生成一個代表這個類的java.lang.Class對象作為方法區這些數據的訪問入口。

            相對于類加載過程的其他階段,加載階段是開發期可控性最強的階段。我們可以通過定制不通的類加載器,也就是ClassLoader來控制二進制字節流的獲取方式。

            關于ClassLoader的介紹,請參照 了解ClassLoader

            2、驗證

            驗證,準備和解析其實都屬于連接階段,而驗證就是連接階段的第一步。這一階段主要是為了確保Class文件的字節流中包含的信息復合當前虛擬機的要求,并且不會危害虛擬機自身的安全。

            主要驗證過程包括:文件格式驗證,元數據驗證,字節碼驗證以及符號引用驗證。

            3、準備

            準備階段正式為類變量分配內存并設置初始值。這里的初始值并不是初始化的值,而是數據類型的默認零值。這里提到的類變量是被static修飾的變量,而不是實例變量。

            關于準備階段為類變量設置零值的唯一例外就是當這個類變量同時也被final修飾,那么在編譯時,就會直接為這個常量賦上目標值。

            4、解析

            解析時虛擬機將常量池中的符號引用替換為直接引用的過程。

            5、初始化

            在準備階段,變量已經賦過一次系統要求的初始值,在初始化階段,則是根據程序員通過程序的主觀計劃區初始化類變量和其他資源。

            Java虛擬機規范規定了有4種情況必須立即對類進行初始化(加載,驗證,準備必須在此之前完成)

            1)當使用new關鍵字實例化對象時,當讀取或者設置一個類的靜態字段(被final修飾的除外)時,以及當調用一個類的靜態方法時,如果類未初始化,則需先初始化。

            2)通過反射機制對類進行調用時,如果類未初始化,則需先初始化。

            3)當初始化一個類時,如果其父類未初始化,先初始化父類

            4)用戶指定的執行主類(含main方法的那個類)在虛擬機啟動時會先被初始化

            除了上面這4種方式,所有引用類的方式都不會觸發初始化,稱為被動引用。如:通過子類引用父類的靜態字段,不會導致子類初始化;通過數組定義來引用類,不會觸發此類的初始化;引用類的靜態常量不會觸發定義常量的類的初始化,因為常量在編譯階段已經被放到常量池中了。

            總結:

            在上述5個過程當中,驗證,準備和解析完全由Java虛擬機主導和控制。只要加載階段和初始化階段程序員可以進行控制。在加載階段可以通過實現自定義的ClassLoader來加載類的二進制流,在初始化階段程序員則可完全按照需求來為類變量賦值。

          posted @ 2012-01-19 11:24 順其自然EVO 閱讀(164) | 評論 (0)編輯 收藏

          Java的動態綁定機制

            Java的動態綁定又稱為運行時綁定。意思就是說,程序會在運行的時候自動選擇調用哪兒個方法。

            一、動態綁定的過程

            例子:

          1. public class Son extends Father  
          2. Son son = new Son();3 son.method();

            1、首先,編譯器根據對象的聲明類型和方法名,搜索相應類(Son)及其父類(Father)的“方法表”,找出所有訪問屬性為public的method方法。

            可能存在多個方法名為method的方法,只是參數類型或數量不同。

            2、然后,根據方法的“簽名”找出完全匹配的方法。

            方法的名稱和參數列表稱為方法的簽名。

            在Java SE 5.0 以前的版本中,覆蓋父類的方法時,要求返回類型必須是一樣的。現在子類覆蓋父類的方法時,允許其返回類型定義為原始類型的子類型。

          1. public Father getFather(){...} //父類中的方法  
          2. public Son getFather(){...} //子類覆蓋父類中的getFather()方法

            3、如果是private、static、final 方法或者是構造器,則編譯器明確地知道要調用哪兒個方法,這種調用方式成為“靜態調用”。

            4、調用方法。

            如果子類Son中定義了 method() 的方法,則直接調用子類中的相應方法;如果子類Son中沒有定義相應的方法,則到其父類中尋找method()方法。

            二、Demo

            1、子類重寫父類中的方法,調用子類中的方法

          1. public class Father{  
          2.     public void method(){  
          3.         System.out.println("父類方法:"+this.getClass());  
          4.   }  
          5. }  
          6. public class Son extends Father{  
          7.     public void method(){  
          8.         System.out.println("子類方法"+this.getClass());  
          9. }  
          10. public static void main(String[] args){  
          11.     Father instance = new Son();  
          12.     instance.method();  
          13.     }  
          14. }  
          15. //結果:子類方法:class Son

            2、子類沒有重寫父類中的方法,所以到父類中尋找相應的方法

          1. public class Father{  
          2.     public void method(){  
          3.         System.out.println("父類方法:"+this.getClass());  
          4.     }  
          5. }  
          6. public class Son extends Father{  
          7.     public static void main(String[] args){  
          8.         Father instance = new Son();  
          9.         instance.method();   
          10.     }  
          11. }  
          12. //結果:父類方法:class Son

            三、動態綁定只是針對對象的方法,對于屬性無效。因為屬性不能被重寫。

          1. public class Father{  
          2.     public String name = "父親屬性";  
          3.     }  
          4. public class Son extends Father{  
          5.     public String name = "孩子屬性";  
          6.     public static void main(String[] args){  
          7.         Father instance = new Son();  
          8.         System.out.println(instance.name);  
          9.     }  
          10. }  
          11. //結果:父親屬性

          posted @ 2012-01-18 10:59 順其自然EVO 閱讀(210) | 評論 (0)編輯 收藏

          Java編碼及網絡傳輸中的編碼問題

               摘要: Java編碼及網絡傳輸中的編碼問題 近來試著FTP搜索,遇到編碼問題,研究了下。  Java內部的String為Unicode編碼,每個字符占兩個字節。  Java編解碼方法如下:String str = "hi好啊me";  byte[] gbkBytes=str.getBytes("GBK");//將String的Unicode編碼轉為GBK編...  閱讀全文

          posted @ 2012-01-17 11:30 順其自然EVO 閱讀(2583) | 評論 (0)編輯 收藏

          Java中刪除數組中重復元素

          這個是一個老問題,但是發現大多數人說的還不夠透。小弟就在這里拋磚引玉了,歡迎拍磚.......

            問題:比如我有一個數組(元素個數為0哈),希望添加進去元素不能重復。

            拿到這樣一個問題,我可能會快速的寫下代碼,這里數組用ArrayList.

          1. private static void testListSet(){  
          2.         List<String> arrays = new ArrayList<String>(){  
          3.             @Override 
          4.             public boolean add(String e) {  
          5.                 for(String str:this){  
          6.                     if(str.equals(e)){  
          7.                         System.out.println("add failed !!!  duplicate element");  
          8.                         return false;  
          9.                     }else{  
          10.                         System.out.println("add successed !!!");  
          11.                     }  
          12.                 }  
          13.                 return super.add(e);  
          14.             }  
          15.         };  
          16.                 arrays.add("a");arrays.add("b");arrays.add("c");arrays.add("b");  
          17.         for(String e:arrays)  
          18.             System.out.print(e);  
          19.     }

            這里我什么都不關,只關心在數組添加元素的時候做下判斷(當然添加數組元素只用add方法),是否已存在相同元素,如果數組中不存在這個元素,就添加到這個數組中,反之亦然。這樣寫可能簡單,但是面臨龐大數組時就顯得笨拙:有100000元素的數組天家一個元素,難道要調用100000次equal嗎?這里是個基礎。

            問題:加入已經有一些元素的數組了,怎么刪除這個數組里重復的元素呢?

            大家知道java中集合總的可以分為兩大類:List與Set。List類的集合里元素要求有序但可以重復,而Set類的集合里元素要求無序但不能重復。那么這里就可以考慮利用Set這個特性把重復元素刪除不就達到目的了,畢竟用系統里已有的算法要優于自己現寫的算法吧。

          1. public static void removeDuplicate(List<People> list){  
          2.    HashSet<People> set = new HashSet<People>(list);  
          3.    list.clear();  
          4.    list.addAll(set);  
          5. }  
          6. ivate static People[] ObjData = new People[]{  
          7.     new People(0"a"),new People(1"b"),new People(0"a"),new People(2"a"),new People(3"c"),  
          8. };

          1. public class People{  
          2.     private int id;  
          3.     private String name;  
          4.       
          5.     public People(int id,String name){  
          6.         this.id = id;  
          7.         this.name = name;  
          8.     }  
          9.       
          10.     @Override 
          11.     public String toString() {  
          12.         return ("id = "+id+" , name "+name);  
          13.     }  
          14.       
          15. }

            上面的代碼,用了一個自定義的People類,當我添加相同的對象時候(指的是含有相同的數據內容),調用removeDuplicate方法發現這樣并不能解決實際問題,仍然存在相同的對象。那么HashSet里是怎么判斷像個對象是否相同的呢?打開HashSet源碼可以發現:每次往里面添加數據的時候,就必須要調用add方法:

          1.       @Override 
          2.      public boolean add(E object) {  
          3.          return backingMap.put(object, this) == null;  
          4.      }

           這里的backingMap也就是HashSet維護的數據,它用了一個很巧妙的方法,把每次添加的Object當作HashMap里面的KEY,本身HashSet對象當作VALUE。這樣就利用了Hashmap里的KEY唯一性,自然而然的HashSet的數據不會重復。但是真正的是否有重復數據,就得看HashMap里的怎么判斷兩個KEY是否相同。

          1.         @Override public V put(K key, V value) {  
          2. 390         if (key == null) {  
          3. 391             return putValueForNullKey(value);  
          4. 392         }  
          5. 393   
          6. 394         int hash = secondaryHash(key.hashCode());  
          7. 395         HashMapEntry<K, V>[] tab = table;  
          8. 396         int index = hash & (tab.length - 1);  
          9. 397         for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {  
          10. 398             if (e.hash == hash && key.equals(e.key)) {  
          11. 399                 preModify(e);  
          12. 400                 V oldValue = e.value;  
          13. 401                 e.value = value;  
          14. 402                 return oldValue;  
          15. 403             }  
          16. 404         }  
          17. 405   
          18. 406         // No entry for (non-null) key is present; create one  
          19. 407         modCount++;  
          20. 408         if (size++ > threshold) {  
          21. 409             tab = doubleCapacity();  
          22. 410             index = hash & (tab.length - 1);  
          23. 411         }  
          24. 412         addNewEntry(key, value, hash, index);  
          25. 413         return null;  
          26. 414     }

            總的來說,這里實現的思路是:遍歷hashmap里的元素,如果元素的hashcode相等(事實上還要對hashcode做一次處理),然后去判斷KEY的eqaul方法。如果這兩個條件滿足,那么就是不同元素。那這里如果數組里的元素類型是自定義的話,要利用Set的機制,那就得自己實現equal與hashmap(這里hashmap算法就不詳細介紹了,我也就理解一點)方法了:

          1. public class People{  
          2.     private int id; //  
          3.     private String name;  
          4.       
          5.     public People(int id,String name){  
          6.         this.id = id;  
          7.         this.name = name;  
          8.     }  
          9.       
          10.     @Override 
          11.     public String toString() {  
          12.         return ("id = "+id+" , name "+name);  
          13.     }  
          14.      
          15.     public int getId() {  
          16.         return id;  
          17.     }  
          18.  
          19.     public void setId(int id) {  
          20.         this.id = id;  
          21.     }  
          22.  
          23.     public String getName() {  
          24.         return name;  
          25.     }  
          26.  
          27.     public void setName(String name) {  
          28.         this.name = name;  
          29.     }  
          30.  
          31.     @Override 
          32.     public boolean equals(Object obj) {  
          33.         if(!(obj instanceof People))  
          34.             return false;  
          35.         People o = (People)obj;  
          36.         if(id == o.getId()&&name.equals(o.getName()))  
          37.             return true;  
          38.         else 
          39.             return false;  
          40.     }  
          41.       
          42.     @Override 
          43.     public int hashCode() {  
          44.         // TODO Auto-generated method stub  
          45.         return id;  
          46.         //return super.hashCode();  
          47.     }  
          48. }

            這里在調用removeDuplicate(list)方法就不會出現兩個相同的people了。



          posted @ 2012-01-16 14:14 順其自然EVO 閱讀(727) | 評論 (0)編輯 收藏

          JVM基礎:JVM內存組成及分配

           Java內存組成介紹:堆(Heap)和非堆(Non-heap)內存

            按照官方的說法:“Java 虛擬機具有一個堆,堆是運行時數據區域,所有類實例和數組的內存均從此處分配。堆是在 Java 虛擬機啟動時創建的。”“在JVM中堆之外的內存稱為非堆內存(Non-heap memory)”。可以看出JVM主要管理兩種類型的內存:堆和非堆。簡單來說堆就是Java代碼可及的內存,是留給開發人員使用的;非堆就是JVM留給 自己用的,所以方法區、JVM內部處理或優化所需的內存(如JIT編譯后的代碼緩存)、每個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法 的代碼都在非堆內存中。

            組成圖

            ◆ 方法棧&本地方法棧:

            線程創建時產生,方法執行時生成棧幀

            ◆ 方法區

            存儲類的元數據信息 常量等

            ◆ 堆

            java代碼中所有的new操作

            ◆ native Memory(C heap)

            Direct Bytebuffer JNI Compile GC;

            堆內存分配

            JVM初始分配的內存由-Xms指定,默認是物理內存的1/64;JVM最大分配的內存由-Xmx指 定,默認是物理內存的1/4。默認空余堆內存小于40%時,JVM就會增大堆直到-Xmx的最大限制;空余堆內存大于70%時,JVM會減少堆直到 -Xms的最小限制。因此服務器一般設置-Xms、-Xmx相等以避免在每次GC 后調整堆的大小。對象的堆內存由稱為垃圾回收器的自動內存管理系統回收。

          組  成詳  解

          Young Generation

          即圖中的Eden + From Space + To Space

          Eden

          存放新生的對象

          Survivor Space

          有兩個,存放每次垃圾回收后存活的對象

          Old Generation

          Tenured Generation 即圖中的Old Space
          主要存放應用程序中生命周期長的存活對象

            非堆內存分配

            JVM使用-XX:PermSize設置非堆內存初始值,默認是物理內存的1/64;由XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的1/4。

          組  成詳  解

          Permanent Generation

          保存虛擬機自己的靜態(refective)數據
          主要存放加載的Class類級別靜態對象如class本身,method,field等等
          permanent generation空間不足會引發full GC

          Code Cache

          用于編譯和保存本地代碼(native code)的內存
          JVM內部處理或優化

            JVM內存限制(最大值)

            JVM內存的最大值跟操作系統有很大的關系。簡單的說就32位處理器雖然 可控內存空間有4GB,但是具體的操作系統會給一個限制,這個限制一般是2GB-3GB(一般來說Windows系統下為1.5G-2G,Linux系統 下為2G-3G),而64bit以上的處理器就不會有限制了。

          posted @ 2012-01-15 00:56 順其自然EVO 閱讀(182) | 評論 (0)編輯 收藏

          JVM調優總結:新一代的垃圾回收算法

          垃圾回收的瓶頸

            傳統分代垃圾回收方式,已經在一定程度上把垃圾回收給應用帶來的負擔降到了最小,把應用的吞吐量推到了一個極限。但是他無法解決的一個問題,就是Full GC所帶來的應用暫停。在一些對實時性要求很高的應用場景下,GC暫停所帶來的請求堆積和請求失敗是無法接受的。這類應用可能要求請求的返回時間在幾百甚至幾十毫秒以內,如果分代垃圾回收方式要達到這個指標,只能把最大堆的設置限制在一個相對較小范圍內,但是這樣有限制了應用本身的處理能力,同樣也是不可接收的。

            分代垃圾回收方式確實也考慮了實時性要求而提供了并發回收器,支持最大暫停時間的設置,但是受限于分代垃圾回收的內存劃分模型,其效果也不是很理想。

            為了達到實時性的要求(其實Java語言最初的設計也是在嵌入式系統上的),一種新垃圾回收方式呼之欲出,它既支持短的暫停時間,又支持大的內存空間分配。可以很好的解決傳統分代方式帶來的問題。

            增量收集的演進

            增量收集的方式在理論上可以解決傳統分代方式帶來的問題。增量收集把對堆空間劃分成一系列內存塊,使用時,先使用其中一部分(不會全部用完),垃圾收集時把之前用掉的部分中的存活對象再放到后面沒有用的空間中,這樣可以實現一直邊使用邊收集的效果,避免了傳統分代方式整個使用完了再暫停的回收的情況。

            當然,傳統分代收集方式也提供了并發收集,但是他有一個很致命的地方,就是把整個堆做為一個內存塊,這樣一方面會造成碎片(無法壓縮),另一方面他的每次收集都是對整個堆的收集,無法進行選擇,在暫停時間的控制上還是很弱。而增量方式,通過內存空間的分塊,恰恰可以解決上面問題。

            Garbage Firest(G1)

            這部分的內容主要參考這里,這篇文章算是對G1算法論文的解讀。我也沒加什么東西了。

            目標

            從設計目標看G1完全是為了大型應用而準備的。

            支持很大的堆

            高吞吐量

            --支持多CPU和垃圾回收線程

            --在主線程暫停的情況下,使用并行收集

            --在主線程運行的情況下,使用并發收

            實時目標:可配置在N毫秒內最多只占用M毫秒的時間進行垃圾回收當然G1要達到實時性的要求,相對傳統的分代回收算法,在性能上會有一些損失。

            算法詳解

            G1可謂博采眾家之長,力求到達一種完美。他吸取了增量收集優點,把整個堆劃分為一個一個等大小的區域(region)。內存的回收和劃分都以region為單位;同時,他也吸取了CMS的特點,把這個垃圾回收過程分為幾個階段,分散一個垃圾回收過程;而且,G1也認同分代垃圾回收的思想,認為不同對象的生命周期不同,可以采取不同收集方式,因此,它也支持分代的垃圾回收。為了達到對回收時間的可預計性,G1在掃描了region以后,對其中的活躍對象的大小進行排序,首先會收集那些活躍對象小的region,以便快速回收空間(要復制的活躍對象少了),因為活躍對象小,里面可以認為多數都是垃圾,所以這種方式被稱為Garbage First(G1)的垃圾回收算法,即:垃圾優先的回收。

           回收步驟:

            初始標記(Initial Marking)

            G1對于每個region都保存了兩個標識用的bitmap,一個為previous marking bitmap,一個為next marking bitmap,bitmap中包含了一個bit的地址信息來指向對象的起始點。

            開始Initial Marking之前,首先并發的清空next marking bitmap,然后停止所有應用線程,并掃描標識出每個region中root可直接訪問到的對象,將region中top的值放入next top at mark start(TAMS)中,之后恢復所有應用線程。

            觸發這個步驟執行的條件為:

            G1定義了一個JVM Heap大小的百分比的閥值,稱為h,另外還有一個H,H的值為(1-h)*Heap Size,目前這個h的值是固定的,后續G1也許會將其改為動態的,根據jvm的運行情況來動態的調整,在分代方式下,G1還定義了一個u以及soft limit,soft limit的值為H-u*Heap Size,當Heap中使用的內存超過了soft limit值時,就會在一次clean up執行完畢后在應用允許的GC暫停時間范圍內盡快的執行此步驟;

            在pure方式下,G1將marking與clean up組成一個環,以便clean up能充分的使用marking的信息,當clean up開始回收時,首先回收能夠帶來最多內存空間的regions,當經過多次的clean up,回收到沒多少空間的regions時,G1重新初始化一個新的marking與clean up構成的環。

            并發標記(Concurrent Marking)

            按照之前Initial Marking掃描到的對象進行遍歷,以識別這些對象的下層對象的活躍狀態,對于在此期間應用線程并發修改的對象的以來關系則記錄到remembered set logs中,新創建的對象則放入比top值更高的地址區間中,這些新創建的對象默認狀態即為活躍的,同時修改top值。

            最終標記暫停(Final Marking Pause)

            當應用線程的remembered set logs未滿時,是不會放入filled RS buffers中的,在這樣的情況下,這些remebered set logs中記錄的card的修改就會被更新了,因此需要這一步,這一步要做的就是把應用線程中存在的remembered set logs的內容進行處理,并相應的修改remembered sets,這一步需要暫停應用,并行的運行。

            存活對象計算及清除(Live Data Counting and Cleanup)

            值得注意的是,在G1中,并不是說Final Marking Pause執行完了,就肯定執行Cleanup這步的,由于這步需要暫停應用,G1為了能夠達到準實時的要求,需要根據用戶指定的最大的GC造成的暫停時間來合理的規劃什么時候執行Cleanup,另外還有幾種情況也是會觸發這個步驟的執行的:

            G1采用的是復制方法來進行收集,必須保證每次的”to space”的空間都是夠的,因此G1采取的策略是當已經使用的內存空間達到了H時,就執行Cleanup這個步驟;

            對于full-young和partially-young的分代模式的G1而言,則還有情況會觸發Cleanup的執行,full-young模式下,G1根據應用可接受的暫停時間、回收young regions需要消耗的時間來估算出一個yound regions的數量值,當JVM中分配對象的young regions的數量達到此值時,Cleanup就會執行;partially-young模式下,則會盡量頻繁的在應用可接受的暫停時間范圍內執行Cleanup,并最大限度的去執行non-young regions的Cleanup。

            展望

            以后JVM的調優或許跟多需要針對G1算法進行調優了。

          posted @ 2012-01-12 10:22 順其自然EVO 閱讀(211) | 評論 (0)編輯 收藏

          僅列出標題
          共394頁: First 上一頁 343 344 345 346 347 348 349 350 351 下一頁 Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 凤山市| 大邑县| 黄陵县| 青海省| 铜梁县| 金湖县| 绵竹市| 卓尼县| 诸城市| 驻马店市| 正镶白旗| 岑溪市| 昂仁县| 台北市| 三都| 安溪县| 乃东县| 石景山区| 泗水县| 娄底市| 福泉市| 镇雄县| 纳雍县| 长乐市| 阿拉善右旗| 泰州市| 大兴区| 三台县| 唐山市| 若羌县| 壤塘县| 福建省| 黄梅县| 和田市| 鹤岗市| 大足县| 自贡市| 中宁县| 乌兰浩特市| 新宁县| 红原县|