獲取程序性能消耗信息的方法、裝置及系統(tǒng)的制作方法
【專利摘要】本申請(qǐng)公開了獲取程序性能消耗信息的方法、裝置及系統(tǒng),其中,所述方法包括:接收攜帶有待分析目標(biāo)信息的分析指令,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng);根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。通過本申請(qǐng),能夠避免用戶手動(dòng)插入代碼的操作過程,而且還可以控制進(jìn)行字節(jié)碼增強(qiáng)的范圍,降低對(duì)實(shí)際的業(yè)務(wù)程序運(yùn)行造成的影響。
【專利說明】獲取程序性能消耗信息的方法、裝置及系統(tǒng)
【技術(shù)領(lǐng)域】
[0001]本申請(qǐng)涉及Java程序性能排查與分析【技術(shù)領(lǐng)域】,特別是涉及獲取程序性能消耗信息的方法、裝置及系統(tǒng)。
【背景技術(shù)】
[0002]在Java程序的性能問題排查和分析工作中,經(jīng)常需要獲取Java程序的執(zhí)行路徑以及路徑上各節(jié)點(diǎn)性能消耗情況,也即需要獲知Java程序中各個(gè)Java方法的執(zhí)行時(shí)間,各個(gè)Java方法之間的調(diào)用關(guān)系,以及Java方法調(diào)用的其他方法的執(zhí)行時(shí)間。為了達(dá)到該目的,一般的實(shí)現(xiàn)方式是在Java方法調(diào)用開頭和結(jié)束處分別增加一段用于記錄當(dāng)前時(shí)間和方法標(biāo)識(shí)的代碼,并把該數(shù)據(jù)設(shè)置到線程變量中;這樣,當(dāng)最上層被調(diào)用的方法的結(jié)束處被調(diào)用時(shí),剛好在線程變量中成對(duì)地產(chǎn)生了包含方法標(biāo)識(shí)信息、方法調(diào)用開始時(shí)間、方法調(diào)用結(jié)束時(shí)間的信息,這就可以計(jì)算出每個(gè)方法執(zhí)行的耗時(shí)時(shí)間。計(jì)算公式是:方法調(diào)用消耗時(shí)間=方法調(diào)用結(jié)束時(shí)間-方法調(diào)用開始時(shí)間。同時(shí),由于方法調(diào)用的開始和結(jié)束都是成對(duì)出現(xiàn)的,通過所有方法調(diào)用的開始和結(jié)束時(shí)間的先后順序,就可以得到方法之間的調(diào)用關(guān)系樹。
[0003]現(xiàn)有技術(shù)中,為了向Java方法調(diào)用開頭和結(jié)束處增加相關(guān)的代碼,一種實(shí)現(xiàn)方式是由技術(shù)人員手工設(shè)置。也就是說,當(dāng)java程序的問題排查人員想要知道某個(gè)Java方法消耗的執(zhí)行時(shí)間以及方法內(nèi)調(diào)用的其他方法的執(zhí)行時(shí)間等信息時(shí),可以手動(dòng)地在各個(gè)需要關(guān)注的Java方法調(diào)用開頭和結(jié)束處增加相關(guān)的代碼。這樣,當(dāng)Java程序運(yùn)行后,就可以得到這些Java方法消耗的執(zhí)行時(shí)間。
[0004]但是,這種實(shí)現(xiàn)方式下需要技術(shù)人員手動(dòng)地修改程序代碼,而且修改之后需要重新部署應(yīng)用來讓這些代碼生效。如果要新增一些關(guān)注點(diǎn),則需要重新在這些關(guān)注點(diǎn)的調(diào)用開頭及結(jié)束處添加代碼并重新部署。所以,這種方式存在硬編碼、代價(jià)大、需要了解應(yīng)用程序的代碼邏輯等缺點(diǎn)。
[0005]為此,現(xiàn)有技術(shù)中還提供了另一種實(shí)現(xiàn)方式,在這種實(shí)現(xiàn)方式中,將前述方式中在Java方法開頭和結(jié)尾處手工增加相關(guān)代碼的操作,修改為通過運(yùn)行時(shí)動(dòng)態(tài)操縱Java方法所在類的字節(jié)碼的方式來實(shí)現(xiàn),也就是說,可以通過字節(jié)碼操縱框架(如ASM)實(shí)現(xiàn)自動(dòng)增加代碼的目的。具體實(shí)現(xiàn)時(shí),需要在JVM (Java Virtual Machine, Java虛擬機(jī))啟動(dòng)參數(shù)中以javaagent參數(shù)指定用于攔截類加載和修改類字節(jié)碼的jar包,JVM啟動(dòng)后,javaagent參數(shù)指定的jar包攔截所有加載的Java類,并在各方法中增加獲取方法執(zhí)行時(shí)間的字節(jié)碼。
[0006]相對(duì)而言,這種方式省去了手工添加排查代碼的麻煩,但是仍然至少存在以下問題:這種方式對(duì)所有加載進(jìn)JVM的Java方法都做了字節(jié)碼修改,這在一定程度上會(huì)影響到被檢查應(yīng)用的代碼執(zhí)行效率。
【發(fā)明內(nèi)容】
[0007]本申請(qǐng)?zhí)峁┝双@取程序性能消耗信息的方法、裝置及系統(tǒng),能夠避免用戶手動(dòng)插入代碼的操作過程,而且還可以控制進(jìn)行字節(jié)碼增強(qiáng)的范圍,降低對(duì)實(shí)際的業(yè)務(wù)程序運(yùn)行造成的影響。
[0008]本申請(qǐng)?zhí)峁┝巳缦路桨?
[0009]一種獲取程序性能消耗信息的方法,包括:
[0010]接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0011]根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0012]在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0013]根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
[0014]一種獲取程序性能消耗信息的方法,包括:
[0015]接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0016]向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令;
[0017]觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊,以便通過所述代理模塊執(zhí)行以下步驟:通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ;通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置;從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回;
[0018]接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn)。
[0019]一種獲取程序性能消耗信息的裝置,包括:
[0020]指令接收單元,用于接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0021]待分析方法確定單元,用于根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0022]字節(jié)碼增強(qiáng)單元,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0023]計(jì)算單元,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
[0024]一種獲取程序性能消耗信息的系統(tǒng),包括客戶端模塊及代理模塊,其中:
[0025]所述客戶端模塊包括:
[0026]信息接收單元,用于接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0027]指令發(fā)送單元,用于向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令;
[0028]觸發(fā)單元,用于觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊;
[0029]結(jié)果展現(xiàn)單元,用于接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn);
[0030]所述代理模塊包括:
[0031]監(jiān)聽單元,用于通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ;
[0032]待分析方法確定單元,用于通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0033]字節(jié)碼增強(qiáng)單元,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0034]計(jì)算單元,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置;
[0035]返回單元,用于從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回。
[0036]根據(jù)本申請(qǐng)?zhí)峁┑木唧w實(shí)施例,本申請(qǐng)公開了以下技術(shù)效果:
[0037]通過本申請(qǐng)實(shí)施例,可以由用戶指定需要分析的方法,并僅對(duì)這些需要分析的方法進(jìn)行自動(dòng)的字節(jié)碼增強(qiáng),以便能夠在需要分析的方法被調(diào)用的過程中,獲取到方法執(zhí)行所耗費(fèi)的時(shí)間,進(jìn)而為排查和分析程序中可能存在的問題提供分析依據(jù)。在該方法中,不僅可以避免用戶手動(dòng)插入代碼的操作過程,而且還可以控制進(jìn)行字節(jié)碼增強(qiáng)的范圍,降低對(duì)實(shí)際的業(yè)務(wù)程序運(yùn)行造成的影響,也避免了不必要的系統(tǒng)開銷。
[0038]當(dāng)然,實(shí)施本申請(qǐng)的任一產(chǎn)品并不一定需要同時(shí)達(dá)到以上所述的所有優(yōu)點(diǎn)。
【專利附圖】
【附圖說明】
[0039]為了更清楚地說明本申請(qǐng)實(shí)施例或現(xiàn)有技術(shù)中的技術(shù)方案,下面將對(duì)實(shí)施例中所需要使用的附圖作簡單地介紹,顯而易見地,下面描述中的附圖僅僅是本申請(qǐng)的一些實(shí)施例,對(duì)于本領(lǐng)域普通技術(shù)人員來講,在不付出創(chuàng)造性勞動(dòng)的前提下,還可以根據(jù)這些附圖獲得其他的附圖。
[0040]圖1是調(diào)用關(guān)系樹不意圖;
[0041]圖2是本申請(qǐng)實(shí)施例提供的方法性能消耗分析結(jié)果的示意圖;
[0042]圖3是本申請(qǐng)實(shí)施例提供的方法的流程圖;
[0043]圖4是本申請(qǐng)實(shí)施例提供的另一方法的流程圖;
[0044]圖5是本申請(qǐng)實(shí)施例提供的裝置的示意圖;
[0045]圖6是本申請(qǐng)實(shí)施例提供的系統(tǒng)的示意圖。
【具體實(shí)施方式】
[0046]下面將結(jié)合本申請(qǐng)實(shí)施例中的附圖,對(duì)本申請(qǐng)實(shí)施例中的技術(shù)方案進(jìn)行清楚、完整地描述,顯然,所描述的實(shí)施例僅僅是本申請(qǐng)一部分實(shí)施例,而不是全部的實(shí)施例?;诒旧暾?qǐng)中的實(shí)施例,本領(lǐng)域普通技術(shù)人員所獲得的所有其他實(shí)施例,都屬于本申請(qǐng)保護(hù)的范圍。
[0047]為了能夠在對(duì)java程序的性能問題進(jìn)行排查和分析時(shí),避免需要人為手動(dòng)修改方法的代碼,同時(shí)也避免所有方法的字節(jié)碼都被增強(qiáng)導(dǎo)致被檢查的應(yīng)用受到影響,本申請(qǐng)實(shí)施例提供了新的獲取程序性能消耗信息的方法。在該方法中,可以由分析人員指定需要分析的方法,然后自動(dòng)實(shí)現(xiàn)對(duì)這些指定方法的字節(jié)碼進(jìn)行增強(qiáng),進(jìn)而獲取到方法在執(zhí)行過程中所需的時(shí)間等信息,供分析人員對(duì)可能存在的問題進(jìn)行排查及分析。也就是說,本申請(qǐng)實(shí)施例提供的方法能夠?qū)崿F(xiàn)自動(dòng)的對(duì)字節(jié)碼進(jìn)行增強(qiáng),避免分析人員手動(dòng)修改方法的代碼,同時(shí),可以實(shí)現(xiàn)僅對(duì)用戶指定的部分方法的字節(jié)碼進(jìn)行增強(qiáng),而不是全部方法,這樣可以降低對(duì)被檢查應(yīng)用自身代碼造成的影響。下面對(duì)具體的實(shí)現(xiàn)方式進(jìn)行詳細(xì)地介紹。
[0048]在具體的實(shí)現(xiàn)方案中,本申請(qǐng)實(shí)施例相當(dāng)于提供了一種用于獲取程序性能消耗信息的工具,從邏輯功能上來看,該工具可以包括兩個(gè)模塊,其中一個(gè)模塊為客戶端模塊(client),另一個(gè)模塊為代理模塊(agent)。
[0049]client模塊主要用于與用戶進(jìn)行交互,例如,可以向用戶提供操作界面,用戶可以在該操作界面上輸入待分析目標(biāo)信息,例如,待分析進(jìn)程的信息、待分析方法的信息、待分析方法所屬的類的信息,等等;在收到用戶提交的待分析目標(biāo)信息之后,還可以觸發(fā)待分析進(jìn)程對(duì)應(yīng)的目標(biāo)JVM實(shí)例(當(dāng)一個(gè)Java程序啟動(dòng)時(shí),對(duì)應(yīng)的JVM實(shí)例就產(chǎn)生了,也就是說JVM實(shí)例對(duì)應(yīng)了一個(gè)獨(dú)立運(yùn)行的Java程序,屬于進(jìn)程級(jí)別)加載指定的agent模塊,與agent模塊建立并保持通信,將待分析目標(biāo)信息發(fā)送給agent模塊,當(dāng)agent模塊返回待分析方法的性能消耗分析結(jié)果(包括方法執(zhí)行所消耗的時(shí)間等)之后,再將其顯示給用戶。
[0050]其中,關(guān)于具體如何觸發(fā)目標(biāo)JVM實(shí)例加載指定的agent,可以有多種方式。例如,其中一種方式可以是將agent模塊的地址寫入到目標(biāo)JVM實(shí)例的啟動(dòng)參數(shù)中,然后重新啟動(dòng)JVM實(shí)例,這樣,JVM實(shí)例在重新啟動(dòng)之后就可以加載agent,之后再由client模塊將用戶輸入的待分析目標(biāo)信息發(fā)送給agent模塊,由agent模塊進(jìn)行后續(xù)的字節(jié)碼增強(qiáng)、信息收集計(jì)算等操作(關(guān)于與agent模塊相關(guān)的內(nèi)容,會(huì)在后文對(duì)agent模塊的介紹中進(jìn)行詳細(xì)說明)。
[0051]當(dāng)然,在利用上述這種方式來觸發(fā)目標(biāo)JVM實(shí)例加載agent模塊時(shí),需要重新啟動(dòng)目標(biāo)JVM實(shí)例,也就是說,每次接收到用戶發(fā)送的分析請(qǐng)求時(shí),都需要重新啟動(dòng)JVM實(shí)例,這勢(shì)必會(huì)對(duì)被檢測程序的正常運(yùn)行造成一定的影響。為了盡量降低這種影響,本申請(qǐng)實(shí)施例中還可以采用另一種方式來觸發(fā)目標(biāo)JVM實(shí)例加載指定的agent模塊。也即,client模塊可以通過Java的attach API來連接目標(biāo)JVM實(shí)例,并通知目標(biāo)JVM實(shí)例加載指定的agent模塊,具體的,就是要根據(jù)待分析進(jìn)程號(hào)attach到待分析進(jìn)程,并指定agent模塊的jar包(jar包是一種Java格式的文件,agent模塊一般就是以jar包的方式提供)地址,這樣目標(biāo)JVM實(shí)例就會(huì)根據(jù)jar包地址去加載指定的agent模塊。也就是說,通過這種方式通知目標(biāo)JVM實(shí)例來加載agent模塊,可以實(shí)現(xiàn)不必重新啟動(dòng)目標(biāo)JVM,就能獲取到所需的性能消耗分析結(jié)果。換言之,對(duì)于用戶而言,可以在目標(biāo)JVM實(shí)例正在運(yùn)行的過程中,隨時(shí)發(fā)出對(duì)指定的方法進(jìn)行性能分析的請(qǐng)求,并不會(huì)造成JVM實(shí)例的重啟。
[0052]agent模塊是用于收集及計(jì)算具體的性能消耗分析結(jié)果的核心邏輯模塊,其需要實(shí)現(xiàn)的功能包括:對(duì)用戶指定的待分析方法進(jìn)行字節(jié)碼增強(qiáng),使得目標(biāo)JVM實(shí)例在運(yùn)行過程中,能夠根據(jù)增強(qiáng)后的字節(jié)碼自動(dòng)將待分析方法開始被調(diào)用時(shí)的當(dāng)前時(shí)間以及方法返回時(shí)的當(dāng)前時(shí)間記錄下來,并保存到一個(gè)指定的位置處;最后,一次調(diào)用過程結(jié)束后,再分別計(jì)算此次調(diào)用過程涉及到的各個(gè)待分析方法在執(zhí)行時(shí)分別消耗的時(shí)間,另外還可以獲取到各個(gè)待分析方法之間的調(diào)用關(guān)系等等,并返回給client模塊向用戶進(jìn)行展現(xiàn)。
[0053]具體實(shí)現(xiàn)時(shí),在目標(biāo)JVM實(shí)例加載了指定的agent模塊之后,agent模塊首先可以創(chuàng)建Server Socket類,同時(shí)在運(yùn)行該語句的計(jì)算機(jī)的指定端口處建立一個(gè)監(jiān)聽服務(wù),來接聽client模塊發(fā)送的信息。例如:
[0054]ServerSocket MyListener=new ServerSocket(600);
[0055]這里指定提供監(jiān)聽服務(wù)的端口是600,一臺(tái)計(jì)算機(jī)可以同時(shí)提供多個(gè)服務(wù),這些不同的服務(wù)之間通過端口號(hào)來區(qū)別,不同的端口號(hào)上提供不同的服務(wù)。為了隨時(shí)監(jiān)聽可能的Client請(qǐng)求,可以執(zhí)行如下的語句:
[0056]Socket LinkSocket=MyListener.accept ()
[0057]該語句調(diào)用了 ServerSocket對(duì)象的accept O方法,這個(gè)方法的執(zhí)行將使Server端的程序(對(duì)應(yīng)于本申請(qǐng)實(shí)施例中的agent模塊)處于等待狀態(tài),程序?qū)⒁恢弊枞钡讲蹲降揭粋€(gè)來自Client端的請(qǐng)求,并返回一個(gè)用于與該Client通信的Socket對(duì)象Link-Socket。此后Server程序只要向這個(gè)Socket對(duì)象讀寫數(shù)據(jù),就可以實(shí)現(xiàn)向遠(yuǎn)端的Client讀寫數(shù)據(jù)。結(jié)束監(jiān)聽時(shí),關(guān)閉ServerSocket對(duì)象:
[0058]Mylistener.close O
[0059]agent模塊創(chuàng)建了 Server Socket類之后,clien模塊可以通過指定端口發(fā)送分析指令,相應(yīng)的,agent模塊就可以從相應(yīng)的端口監(jiān)聽到clien模塊發(fā)送的分析指令。該分析指令是由client模塊根據(jù)用戶提交的待分析目標(biāo)信息(包括待分析進(jìn)程的信息、待分析方法的信息、類的信息等)生成的。因此,相當(dāng)于通過這種方式,將用戶提交的待分析目標(biāo)信息傳遞給agent模塊。
[0060]接下來,agent模塊就可以根據(jù)分析指令中攜帶的待分析目標(biāo)信息確定出此次需要分析哪些方法,然后在目標(biāo)JVM實(shí)例已經(jīng)加載的類中找到這些待分析方法的字節(jié)碼,對(duì)其進(jìn)行字節(jié)碼增強(qiáng)。需要說明的是,一般情況下,都是需要對(duì)多個(gè)方法的性能消耗情況進(jìn)行分析,也就是說,用戶在發(fā)起一個(gè)分析請(qǐng)求時(shí),可能包括多個(gè)待分析方法。在實(shí)際應(yīng)用中,為了能夠讓用戶能夠指定其需要關(guān)注的方法,可以有多種方式,并且根據(jù)該指定方式的不同,agent模塊確定待分析方法的方式也會(huì)有所不同。
[0061]例如,在一種實(shí)現(xiàn)方式下,可以允許用戶直接輸入其需要關(guān)注的各個(gè)方法的名稱等標(biāo)識(shí)信息,也就是說,在client模塊提供的用戶界面上,用戶可以直接輸入待分析的進(jìn)程號(hào),或者輸入各個(gè)待分析方法的名稱等標(biāo)識(shí)信息,或者輸入各個(gè)待分析方法所屬的類的名稱等標(biāo)識(shí)信息。這樣,client模塊發(fā)送給agent模塊的分析指令中,相當(dāng)于直接攜帶了各個(gè)待分析方法的名稱以及各自所屬的類名稱,因此,agent模塊可以直接根據(jù)類名稱以及方法名稱定為到待分析方法,進(jìn)而進(jìn)行后續(xù)的字節(jié)碼增強(qiáng)等操作即可。
[0062]以上這種直接指定待分析方法的名稱等標(biāo)識(shí)信息的方式,一般適用于待分析方法的數(shù)目比較少的情況,但在實(shí)際應(yīng)用中,可能存在需要對(duì)多個(gè)方法進(jìn)行分析的情形,此時(shí),如果仍然直接輸入各個(gè)待分析方法的名稱,則一方面需要耗費(fèi)用戶的時(shí)間,降低分析效率,另一方面需要用戶對(duì)各個(gè)方法及其調(diào)用關(guān)系等非常了解,對(duì)用戶的知識(shí)儲(chǔ)備程度要求比較高。因此,在本申請(qǐng)實(shí)施例中還為用戶提供了另一種指定待分析方法的方式。
[0063]在這種方式中,考慮到一次分析過程需要分析的多個(gè)方法之間可能存在調(diào)用關(guān)系,并且根據(jù)這種調(diào)用關(guān)系可以組成一棵調(diào)用關(guān)系樹,因此,在指定這些待分析方法時(shí),可以使用相對(duì)簡化的方法。
[0064]為了便于理解,下面首先對(duì)調(diào)用關(guān)系樹的相關(guān)概念進(jìn)行簡單的介紹。在一棵調(diào)用關(guān)系樹中,處于根節(jié)點(diǎn)上的方法相當(dāng)于是樹的入口,樹的第二層節(jié)點(diǎn)是根節(jié)點(diǎn)依賴的方法,第三層節(jié)點(diǎn)是第二層節(jié)點(diǎn)依賴的方法,以此類推。例如,參見圖1,假設(shè)其為一個(gè)調(diào)用關(guān)系樹,箭頭表示方法之間的調(diào)用關(guān)系,其中,各個(gè)節(jié)點(diǎn)對(duì)應(yīng)不同的方法,方法A位于根節(jié)點(diǎn),方法A依賴方法B及方法C,方法B依賴方法D,方法C依賴方法E。也就是說,如果某線程需要調(diào)用方法A,則在方法A執(zhí)行的過程中,需要先調(diào)用方法B及方法C,在方法B被調(diào)用后,還會(huì)調(diào)用方法D,方法D執(zhí)行完畢返回之后,方法B才會(huì)返回;在另一分支上,方法C被調(diào)用后,還需要調(diào)用方法E,方法E被調(diào)用完畢返回之后,方法C才會(huì)返回,方法B及方法C都返回之后,方法A才會(huì)返回。
[0065]如果在某次分析需求中,用戶恰好是需要對(duì)圖1中的方法A、B、C、D、E進(jìn)行排查分析,則相當(dāng)于是對(duì)圖1所示的調(diào)用關(guān)系樹上的各個(gè)節(jié)點(diǎn)進(jìn)行分析,而這些節(jié)點(diǎn)其實(shí)可以通過根節(jié)點(diǎn)以及樹的層次來表示。例如,在已知該調(diào)用關(guān)系樹的結(jié)構(gòu)的前提下,如果又已知根節(jié)點(diǎn)為方法A,則第一層節(jié)點(diǎn)就是方法A,第二層節(jié)點(diǎn)是方法B及方法C,第三層是方法D及方法E。因此,對(duì)于這種情況,用戶在指定待分析方法的信息時(shí),可以只輸入該調(diào)用關(guān)系樹的入口方法的名稱以及需分析的層次深度。例如,假設(shè)需要對(duì)方法A、B、C、D、E進(jìn)行排查分析,則用戶可以指定入口方法為方法A,需要分析的層次深度為3層,則agent模塊就可以獲知,是需要對(duì)以方法A為根節(jié)點(diǎn)的調(diào)用關(guān)系樹中的前三層節(jié)點(diǎn)進(jìn)行分析。因此,對(duì)于agent模塊而言,只要再獲知到以A為根節(jié)點(diǎn)的調(diào)用關(guān)系樹,就可以獲知具體是需要對(duì)哪些方法進(jìn)行分析。
[0066]而在具體實(shí)現(xiàn)時(shí),agent模塊是可以獲取到方法之間的調(diào)用關(guān)系信息的。具體的,agent模塊在接收到client模塊發(fā)送的分析指令后,可以從中提取出入口方法的標(biāo)識(shí)信息(以名稱為例),以及該入口方法所屬的類的名稱,因此,可以首先從目標(biāo)JVM實(shí)例已加載的類中找到該類,并從內(nèi)存中獲取到該類的字節(jié)碼,接下來就可以采用字節(jié)碼分析的方式,對(duì)該類中的各個(gè)方法進(jìn)行靜態(tài)的調(diào)用關(guān)系分析。
[0067]其中,所謂靜態(tài)的調(diào)用關(guān)系是相對(duì)于動(dòng)態(tài)的調(diào)用關(guān)系而言的。動(dòng)態(tài)的調(diào)用關(guān)系是指在程序運(yùn)行過程中各個(gè)方法實(shí)際被調(diào)用時(shí)所體現(xiàn)出的關(guān)系。而靜態(tài)的調(diào)用關(guān)系與具體的程序運(yùn)行過程無關(guān),即,不運(yùn)行相關(guān)程序的前提下分析出的調(diào)用關(guān)系。總之,通過靜態(tài)的調(diào)用關(guān)系分析,就可以得到以用戶提交的入口方法為根節(jié)點(diǎn)時(shí),調(diào)用關(guān)系樹的結(jié)構(gòu),并且可以確定出各個(gè)節(jié)點(diǎn)上對(duì)應(yīng)的方法,進(jìn)而再根據(jù)用戶提交的需要分析的層次深度,就可以獲取到從根節(jié)點(diǎn)到該層次深度的各層節(jié)點(diǎn)對(duì)應(yīng)的方法,將這些方法確定為待分析方法即可。
[0068]例如,假設(shè)用戶提交的待分析目標(biāo)信息中包括某個(gè)Java類的名稱以及該類下的某個(gè)方法A的名稱,則具體進(jìn)行靜態(tài)的調(diào)用關(guān)系分析時(shí),可以首先根據(jù)這個(gè)Java類和方法A,從目標(biāo)JVM實(shí)例中獲取已加載的這個(gè)類的字節(jié)碼,對(duì)這些字節(jié)碼中的內(nèi)容進(jìn)行解析。通過分析這個(gè)類中該方法A的字節(jié)碼,可以獲得這個(gè)方法A中依賴的類和方法列表。再根據(jù)這次分析出來的類和方法列表,遍歷列表中的每一項(xiàng)進(jìn)行同樣的分析,對(duì)每一個(gè)類和方法都分析出方法內(nèi)部的依賴,每一次分析,都能在用戶提交的根節(jié)點(diǎn)上更深入一層,直到分析層次達(dá)到分析指令中指定的分析層次深度,將之前每一層上分析出的方法均確定為待分析方法。
[0069]其中,具體在分析字節(jié)碼時(shí)可以使用ASM框架(ASM是一個(gè)Java字節(jié)碼操縱框架,它可以直接以二進(jìn)制形式動(dòng)態(tài)地生成stub類或其他代理類,或者在裝載時(shí)動(dòng)態(tài)地修改類),通過實(shí)現(xiàn)MethodVisitor類的子類來訪問被分析類的字節(jié)碼,繼承MethodVisitor類的VisitMethodInsn方法,訪問分析代碼中對(duì)其他類和方法的調(diào)用事件。對(duì)如下的調(diào)用方法的操作:INVOKEDYNAMIC、INVOKEINTERFACE、INVOKESPECIAL、INVOKESTATIC、INVOKEVIRTUAL進(jìn)行過濾,并把這些操作碼的兩個(gè)操作數(shù):類名和方法名,記錄下來,最終達(dá)到靜態(tài)的調(diào)用關(guān)系分析的目的。
[0070]需要說明的是,在實(shí)際應(yīng)用中,一個(gè)方法作為根節(jié)點(diǎn)時(shí),其調(diào)用關(guān)系樹的各個(gè)層次上可能均包括多個(gè)節(jié)點(diǎn),用戶可能確實(shí)是需要對(duì)其中前N層節(jié)點(diǎn)進(jìn)行分析,但是可能并不是前N層的所有節(jié)點(diǎn)都需要關(guān)注,也即可能只需要關(guān)注前N層節(jié)點(diǎn)中的一部分。此時(shí),如果這一部分節(jié)點(diǎn)之間能夠體現(xiàn)出一些共性,也可以允許用戶通過指定這些共性來進(jìn)一步限制待分析方法的范圍。這樣可以使得進(jìn)行字節(jié)碼增強(qiáng)的范圍進(jìn)一步縮小。例如,用戶只需要對(duì)前N層節(jié)點(diǎn)中某個(gè)包中的方法進(jìn)行關(guān)注,則可以在client模塊的用戶界面中輸入入口方法的名稱、需要關(guān)注的層次深度N的同時(shí),還輸入該需要關(guān)注的包的名稱;這樣,agent模塊在通過字節(jié)碼分析獲知待分析方法時(shí),在分析出各層上的方法之后,還需要判斷各個(gè)方法的路徑中是否包含該目標(biāo)包的名稱,如果包含,則作為待分析方法,后續(xù)會(huì)進(jìn)行字節(jié)碼增強(qiáng),否則,不會(huì)作為待分析方法,后續(xù)也不會(huì)再對(duì)其進(jìn)行字節(jié)碼增強(qiáng)。
[0071]例如,假設(shè)用戶在client模塊提供的命令行中輸入如下的命令:
[0072]sudo -U admin -H triton -E mCalITree 29375com.taoba0.mitem.sc.service,imp1.ScItemMapServiceImpIgetItemMapByScItemldS^comX.taobao\..氺$
[0073]其中,mCalITree指定分析的類型為代碼調(diào)用時(shí)間樹,29375為待分析的進(jìn)程id,com.taoba0.mitem.sc.service, imp 1.ScltemMapServiceImpl 為待分析的 java 類名,getItemMapByScItemId為待分析的java方法名,5是需要分析的層次深度,也即表示需要分析getItemMapByScItemId方法內(nèi)部調(diào)用5層次以內(nèi)的方法調(diào)用,"com\.taobao\..*$是一個(gè)正則表達(dá)式,指示選定的包名,也即只需要對(duì)路徑中包含有該包名的方法進(jìn)行分析。
[0074]總之,在具體實(shí)現(xiàn)時(shí),各個(gè)待分析方法的名稱要么是由用戶直接輸入的,要么可以由agent模塊通過字節(jié)碼分析獲知。在獲知了需要對(duì)哪些方法進(jìn)行分析之后,agent模塊就可以在已加載的類中找到各個(gè)方法的字節(jié)碼,進(jìn)行字節(jié)碼增強(qiáng)。其中,具體進(jìn)行字節(jié)碼增強(qiáng)時(shí)可以采用與已有技術(shù)中相同的方式來實(shí)現(xiàn)。例如,agent模塊根據(jù)字節(jié)碼分析得到待分析方法的調(diào)用關(guān)系樹后,接著就可以針對(duì)調(diào)用路徑列表中的所有方法進(jìn)行字節(jié)碼增強(qiáng)。在這些類的這些方法都增加下面的邏輯:在方法開頭處記錄當(dāng)前時(shí)間并設(shè)置當(dāng)前時(shí)間和當(dāng)前方法名到指定位置(例如,當(dāng)前線程的緩存),在方法返回處記錄當(dāng)前時(shí)間并設(shè)置當(dāng)前時(shí)間和當(dāng)前方法名到該指定位置??傊?,通過字節(jié)碼增強(qiáng),可以達(dá)到與手動(dòng)地在待分析方法的開頭及結(jié)尾處插入代碼相同的效果,即可以獲取到待分析方法被調(diào)用時(shí)以及返回時(shí)的時(shí)間,供后續(xù)的分析使用。也就是說,對(duì)應(yīng)每個(gè)待分析方法而言,都會(huì)成對(duì)地記錄下兩個(gè)時(shí)間點(diǎn),這兩個(gè)時(shí)間點(diǎn)之間的時(shí)間差即可作為該待分析方法在運(yùn)行時(shí)所消耗的時(shí)間長度。
[0075]需要說明的是,在待分析進(jìn)程運(yùn)行的過程中,實(shí)際上由具體的線程進(jìn)行具體的方法調(diào)用操作,其中,線程對(duì)應(yīng)具體的業(yè)務(wù)邏輯。換言之,一個(gè)待分析進(jìn)程中可能需要實(shí)現(xiàn)多個(gè)業(yè)務(wù)邏輯,每個(gè)業(yè)務(wù)邏輯需要通過各自的線程來實(shí)現(xiàn),每個(gè)線程在執(zhí)行具體的業(yè)務(wù)邏輯時(shí),都可能需要調(diào)用具體的方法。當(dāng)然,對(duì)于相互之間存在依賴關(guān)系的方法而言,會(huì)在同一個(gè)線程中被調(diào)用。例如,線程I調(diào)用了方法A,其中方法A依賴方法B,方法B還依賴方法C,則在線程I中,方法A、B、C都會(huì)被調(diào)用。因此,對(duì)于前述對(duì)某調(diào)用關(guān)系樹下指定層次深度的方法進(jìn)行分析的情況下,如果該調(diào)用關(guān)系樹的根節(jié)點(diǎn)上的入口方法在某線程中被調(diào)用,則該調(diào)用關(guān)系樹上其他節(jié)點(diǎn)的方法也會(huì)在該線程中被調(diào)用。各個(gè)待分析方法被調(diào)用及返回時(shí),都可以將記錄下的調(diào)用時(shí)間以及返回時(shí)間記錄到該線程緩存中。當(dāng)然,由于一次調(diào)用過程中會(huì)涉及到多個(gè)待分析方法,為了避免混淆,在記錄時(shí)間點(diǎn)信息的同時(shí),還需要記錄下對(duì)應(yīng)的待分析方法的名稱等標(biāo)識(shí)信息,這樣才可以區(qū)分出各個(gè)待分析方法分別在何時(shí)被調(diào)用、何時(shí)返回。
[0076]以上提到了“一次調(diào)用過程”的概念,該概念在本申請(qǐng)實(shí)施例中主要是指對(duì)于入口方法的一次調(diào)用過程。也即對(duì)于一個(gè)入口方法而言,從該方法被調(diào)用,到該方法返回,就相當(dāng)于經(jīng)歷了一次調(diào)用過程。當(dāng)然,根據(jù)前文所述的調(diào)用關(guān)系樹中各個(gè)方法之間的關(guān)系可知,在該入口方法返回之前還有其他的待分析方法被調(diào)用之后又返回。也就是說,入口方法的一次調(diào)用過程中可能會(huì)涉及到對(duì)其他待分析方法的一次或多次調(diào)用,但無論是入口方法還是其他待分析方法,在每次調(diào)用時(shí)都可以記錄下被調(diào)用時(shí)間及返回時(shí)間。
[0077]相應(yīng)的,agent模塊可以識(shí)別入口方法的調(diào)用和返回,以此判斷一次調(diào)用過程是否結(jié)束,如果是,則觸發(fā)agent的算法程序收集和分析調(diào)用時(shí)間數(shù)據(jù)。具體進(jìn)行判斷時(shí),可以通過線程緩存中維護(hù)的當(dāng)前線程中最早被調(diào)用并輸出調(diào)用時(shí)間的方法的標(biāo)識(shí)來實(shí)現(xiàn)的。也即,在線程緩存中出現(xiàn)第一個(gè)方法標(biāo)識(shí)及其對(duì)應(yīng)的調(diào)用時(shí)間信息時(shí),就可以將該方法確定為入口方法;之后,每次一個(gè)方法返回時(shí),都可以判斷當(dāng)前返回的方法是否為這個(gè)入口方法,如果是則說明一次從根節(jié)點(diǎn)開始的調(diào)用過程已經(jīng)結(jié)束,agent模塊就可以收集線程緩存中的數(shù)據(jù)進(jìn)行計(jì)算和整理,將整理后的數(shù)據(jù)返回給client模塊之后,可以清空線程緩存。
[0078]需要說明的是,在本申請(qǐng)實(shí)施例中,在向用戶展示性能消耗分析結(jié)果時(shí),是分別對(duì)每次調(diào)用過程中獲取到的分析結(jié)果進(jìn)行展現(xiàn),也就是說,在一個(gè)線程中,某方法可能會(huì)被調(diào)用多次,但是在本申請(qǐng)實(shí)施例中,每調(diào)用一次,都可以展現(xiàn)出這次調(diào)用過程中各個(gè)待分析方法的執(zhí)行耗時(shí)等信息,而不會(huì)對(duì)同一方法在不同調(diào)用過程中的耗時(shí)進(jìn)行累加。
[0079]另外需要說明的是,在本申請(qǐng)實(shí)施例中,除了可以向用戶返回各個(gè)待分析方法的執(zhí)行耗時(shí)信息之外,還可以根據(jù)返回各個(gè)待分析方法之間的調(diào)用關(guān)系信息,使得用戶在獲知各個(gè)方法在執(zhí)行中所消耗的時(shí)間之外,還可以獲知各個(gè)方法之間具有怎樣的調(diào)用關(guān)系,為其具體的排查分析可能存在的問題提供了更多的依據(jù)。例如,某次分析過程返回的分析結(jié)果如圖2所示,其中每一行對(duì)應(yīng)一個(gè)方法,不僅顯示有各個(gè)方法的執(zhí)行耗時(shí),還通過每一行之間的層次體現(xiàn)出方法之間的調(diào)用關(guān)系。
[0080]總之,在本申請(qǐng)實(shí)施例中,可以由用戶指定需要分析的方法,并僅對(duì)這些需要分析的方法進(jìn)行自動(dòng)的字節(jié)碼增強(qiáng),以便能夠在需要分析的方法被調(diào)用的過程中,獲取到方法執(zhí)行所耗費(fèi)的時(shí)間,進(jìn)而為排查和分析程序中可能存在的問題提供分析依據(jù)。在該方法中,不僅可以避免用戶手動(dòng)插入代碼的操作過程,而且還可以控制進(jìn)行字節(jié)碼增強(qiáng)的范圍,降低對(duì)實(shí)際的業(yè)務(wù)程序運(yùn)行造成的影響,也避免了不必要的系統(tǒng)開銷。
[0081]綜上所述,從前述的agent模塊角度而言,本申請(qǐng)實(shí)施例首先提供了一種獲取程序性能消耗信息的方法,參見圖3,該方法可以包括:
[0082]S301:接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0083]S302:根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0084]S303:在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0085]S304:根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
[0086]在計(jì)算得到性能消耗分析結(jié)果之后可以保存到所述指定位置,之后可以從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回。
[0087]其中,在一次分析需求中,待分析方法可能是一個(gè)或多個(gè),用戶輸入的待分析目標(biāo)信息中,待分析方法的信息可以直接是各個(gè)待分析方法的名稱等標(biāo)識(shí)信息,這樣,agent模塊可以直接根據(jù)各個(gè)待分析方法的標(biāo)識(shí)信息,確定出需要分析的是哪些方法。
[0088]其中,如果各個(gè)待分析方法根據(jù)調(diào)用關(guān)系可組成調(diào)用關(guān)系樹,則用戶在輸入待分析方法的信息時(shí),可以僅輸入入口方法的標(biāo)識(shí)信息,以及所需分析的層次深度;其中,入口方法就是調(diào)用關(guān)系樹的根節(jié)點(diǎn)對(duì)應(yīng)的待分析方法;這樣,agent模塊具體在確定待分析方法時(shí),可以首先在待分析進(jìn)程加載的類中查找入口方法對(duì)應(yīng)的類的字節(jié)碼;然后基于字節(jié)碼進(jìn)行靜態(tài)的調(diào)用層次分析,確定從入口方法開始每一層上的方法分別依賴的方法及其對(duì)應(yīng)的類,直到分析到所述層次深度;然后,根據(jù)各層上確定出的方法確定待分析方法。
[0089]其中,具體在根據(jù)各層上確定出的方法確定待分析方法時(shí),可以直接將各個(gè)層上確定出的方法全部確定為所述待分析方法。
[0090]或者用戶在輸入待分析目標(biāo)信息時(shí),還可以對(duì)目標(biāo)包的名稱進(jìn)行限制,此時(shí),具體在根據(jù)各層上確定出的方法確定待分析方法時(shí),可以將各個(gè)層上確定出的所述方法中,路徑中包含所述目標(biāo)包的名稱信息的方法確定為所述待分析方法。這樣可以進(jìn)一步減少字節(jié)碼增強(qiáng)的操作范圍。
[0091]在本申請(qǐng)實(shí)施例中,可以在每完成一次調(diào)用過程之后,對(duì)此次調(diào)用過程中涉及到的各個(gè)待分析方法的性能消耗情況進(jìn)行計(jì)算統(tǒng)計(jì),因此,agent模塊還需要能夠判斷出是否完成一次調(diào)用過程。具體實(shí)現(xiàn)時(shí),可以在每次有待分析方法的返回時(shí)間被記錄到所述指定位置時(shí),判斷該返回的方法是否為所述入口方法;如果是,則確定一次調(diào)用過程結(jié)束,并對(duì)此次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果進(jìn)行計(jì)算。
[0092]具體在從指定位置讀取待分析方法的性能消耗分析結(jié)果并返回時(shí),可以是從所述指定位置讀取所述待分析方法分別在每次調(diào)用過程中的性能消耗分析結(jié)果并返回。也即,最終返回給用戶的是每次調(diào)用過程中各個(gè)方法在執(zhí)行時(shí)耗費(fèi)的時(shí)間。這樣可以更好的為排查分析程序問題提供依據(jù)。
[0093]另外,從client模塊的角度,本申請(qǐng)實(shí)施例還提供了一種獲取程序性能消耗信息的方法,參見圖4,該方法可以包括:
[0094]S401:接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0095]S402:向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令;
[0096]S403:觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊(其中,可以通過attach的方式連接到待分析進(jìn)程對(duì)應(yīng)的JVM,并通知該JVM加載指定的代理模塊),以便通過所述代理模塊執(zhí)行以下步驟:通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ;通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置;從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回;
[0097]S404:接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn)。
[0098]與本申請(qǐng)實(shí)施例提供的前述agent模塊角度的獲取程序性能消耗信息的方法相對(duì)應(yīng),本申請(qǐng)實(shí)施例還提供了一種獲取程序性能消耗信息的裝置,參見圖5,該裝置可以包括:
[0099]指令接收單元501,用于接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0100]待分析方法確定單元502,用于根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0101]字節(jié)碼增強(qiáng)單元503,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0102]計(jì)算單元504,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
[0103]其中,在一次分析需求中,待分析方法可能是一個(gè)或多個(gè),用戶輸入的待分析目標(biāo)信息中,待分析方法的信息可以直接是各個(gè)待分析方法的名稱等標(biāo)識(shí)信息,這樣,agent模塊可以直接根據(jù)各個(gè)待分析方法的標(biāo)識(shí)信息,確定出需要分析的是哪些方法。
[0104]其中,如果各個(gè)待分析方法根據(jù)調(diào)用關(guān)系可組成調(diào)用關(guān)系樹,則用戶在輸入待分析方法的信息時(shí),可以僅輸入入口方法的標(biāo)識(shí)信息,以及所需分析的層次深度;其中,入口方法就是調(diào)用關(guān)系樹的根節(jié)點(diǎn)對(duì)應(yīng)的待分析方法;這樣,agent模塊具體在確定待分析方法時(shí),可以首先在待分析進(jìn)程加載的類中查找入口方法對(duì)應(yīng)的類的字節(jié)碼;然后基于字節(jié)碼進(jìn)行靜態(tài)的調(diào)用層次分析,確定從入口方法開始每一層上的方法分別依賴的方法及其對(duì)應(yīng)的類,直到分析到所述層次深度;然后,根據(jù)各層上確定出的方法確定待分析方法。
[0105]其中,具體在根據(jù)各層上確定出的方法確定待分析方法時(shí),可以直接將各個(gè)層上確定出的方法全部確定為所述待分析方法。
[0106]或者用戶在輸入待分析目標(biāo)信息時(shí),還可以對(duì)目標(biāo)包的名稱進(jìn)行限制,此時(shí),具體在根據(jù)各層上確定出的方法確定待分析方法時(shí),可以將各個(gè)層上確定出的所述方法中,路徑中包含所述目標(biāo)包的名稱信息的方法確定為所述待分析方法。這樣可以進(jìn)一步減少字節(jié)碼增強(qiáng)的操作范圍。
[0107]在本申請(qǐng)實(shí)施例中,可以在每完成一次調(diào)用過程之后,對(duì)此次調(diào)用過程中涉及到的各個(gè)待分析方法的性能消耗情況進(jìn)行計(jì)算統(tǒng)計(jì),因此,agent模塊還需要能夠判斷出是否完成一次調(diào)用過程。具體實(shí)現(xiàn)時(shí),可以在每次有待分析方法的返回時(shí)間被記錄到所述指定位置時(shí),判斷該返回的方法是否為所述入口方法;如果是,則確定一次調(diào)用過程結(jié)束,并對(duì)此次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果進(jìn)行計(jì)算。
[0108]具體在從指定位置讀取待分析方法的性能消耗分析結(jié)果并返回時(shí),可以是從所述指定位置讀取所述待分析方法分別在每次調(diào)用過程中的性能消耗分析結(jié)果并返回。也即,最終返回給用戶的是每次調(diào)用過程中各個(gè)方法在執(zhí)行時(shí)耗費(fèi)的時(shí)間。這樣可以更好的為排查分析程序問題提供依據(jù)
[0109]另外,本申請(qǐng)實(shí)施例還提供了一種獲取程序性能消耗信息的系統(tǒng),參見圖6,該系統(tǒng)可以包括客戶端模塊601及代理模塊602,其中:
[0110]所述客戶端模塊601可以包括:
[0111]信息接收單元6011,用于接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息;
[0112]指令發(fā)送單元6012,用于向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令;
[0113]觸發(fā)單元6013,用于觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊;
[0114]結(jié)果展現(xiàn)單元6014,用于接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn);
[0115]所述代理模塊602包括:
[0116]監(jiān)聽單元6021,用于通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ;
[0117]待分析方法確定單元6022,用于通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;
[0118]字節(jié)碼增強(qiáng)單元6023,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;
[0119]計(jì)算單元6024,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置;
[0120]返回單元6025,用于從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回。
[0121]通過以上的實(shí)施方式的描述可知,本領(lǐng)域的技術(shù)人員可以清楚地了解到本申請(qǐng)可借助軟件加必需的通用硬件平臺(tái)的方式來實(shí)現(xiàn)?;谶@樣的理解,本申請(qǐng)的技術(shù)方案本質(zhì)上或者說對(duì)現(xiàn)有技術(shù)做出貢獻(xiàn)的部分可以以軟件產(chǎn)品的形式體現(xiàn)出來,該計(jì)算機(jī)軟件產(chǎn)品可以存儲(chǔ)在存儲(chǔ)介質(zhì)中,如ROM/RAM、磁碟、光盤等,包括若干指令用以使得一臺(tái)計(jì)算機(jī)設(shè)備(可以是個(gè)人計(jì)算機(jī),服務(wù)器,或者網(wǎng)絡(luò)設(shè)備等)執(zhí)行本申請(qǐng)各個(gè)實(shí)施例或者實(shí)施例的某些部分所述的方法。
[0122]本說明書中的各個(gè)實(shí)施例均采用遞進(jìn)的方式描述,各個(gè)實(shí)施例之間相同相似的部分互相參見即可,每個(gè)實(shí)施例重點(diǎn)說明的都是與其他實(shí)施例的不同之處。尤其,對(duì)于系統(tǒng)或系統(tǒng)實(shí)施例而言,由于其基本相似于方法實(shí)施例,所以描述得比較簡單,相關(guān)之處參見方法實(shí)施例的部分說明即可。以上所描述的系統(tǒng)及系統(tǒng)實(shí)施例僅僅是示意性的,其中所述作為分離部件說明的單元可以是或者也可以不是物理上分開的,作為單元顯示的部件可以是或者也可以不是物理單元,即可以位于一個(gè)地方,或者也可以分布到多個(gè)網(wǎng)絡(luò)單元上??梢愿鶕?jù)實(shí)際的需要選擇其中的部分或者全部模塊來實(shí)現(xiàn)本實(shí)施例方案的目的。本領(lǐng)域普通技術(shù)人員在不付出創(chuàng)造性勞動(dòng)的情況下,即可以理解并實(shí)施。
[0123]以上對(duì)本申請(qǐng)所提供的獲取程序性能消耗信息的方法、裝置及系統(tǒng),進(jìn)行了詳細(xì)介紹,本文中應(yīng)用了具體個(gè)例對(duì)本申請(qǐng)的原理及實(shí)施方式進(jìn)行了闡述,以上實(shí)施例的說明只是用于幫助理解本申請(qǐng)的方法及其核心思想;同時(shí),對(duì)于本領(lǐng)域的一般技術(shù)人員,依據(jù)本申請(qǐng)的思想,在【具體實(shí)施方式】及應(yīng)用范圍上均會(huì)有改變之處。綜上所述,本說明書內(nèi)容不應(yīng)理解為對(duì)本申請(qǐng)的限制。
【權(quán)利要求】
1.一種獲取程序性能消耗信息的方法,其特征在于,包括: 接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息; 根據(jù)所述待分析目標(biāo)信息,確定待分析方法; 在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置; 根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
2.根據(jù)權(quán)利要求1所述的方法,其特征在于,所述待分析方法為一個(gè)或多個(gè),所述待分析方法的信息包括各個(gè)待分析方法的標(biāo)識(shí)信息; 所述根據(jù)所述待分析目標(biāo)信息,確定待分析方法包括: 根據(jù)所述各個(gè)待分析方法的標(biāo)識(shí)信息,確定待分析方法。
3.根據(jù)權(quán)利要求1所述的方法,其特征在于,所述待分析方法為多個(gè)方法,且各個(gè)待分析方法根據(jù)調(diào)用關(guān)系可組成調(diào)用關(guān)系樹,所述待分析方法的信息包括入口方法的標(biāo)識(shí)信息,以及所需分析的層次深度;所述入口方法為所述調(diào)用關(guān)系樹的根節(jié)點(diǎn)對(duì)應(yīng)的待分析方法; 所述根據(jù)所述待分析目標(biāo)信息,確定待分析方法包括: 在所述待分析進(jìn)程加載的類中查找所述入口方法對(duì)應(yīng)的類的字節(jié)碼; 基于字節(jié)碼進(jìn)行靜態(tài)的調(diào)用層次分析,確定從所述入口方法開始每一層上的方法分別依賴的方法及其對(duì)應(yīng)的類,直到分析到所述層次深度; 根據(jù)各層上確定出的方法確定所述待分析方法。
4.根據(jù)權(quán)利要求3所述的方法,其特征在于,所述根據(jù)各層上確定出的方法確定所述待分析方法包括: 將各個(gè)層上確定出的方法全部確定為所述待分析方法。
5.根據(jù)權(quán)利要求3所述的方法,其特征在于,所述待分析方法的信息還包括目標(biāo)包的名稱信息,所述根據(jù)各層上確定出的方法確定所述待分析方法包括: 將各個(gè)層上確定出的所述方法中,路徑中包含所述目標(biāo)包的名稱信息的方法確定為所述待分析方法。
6.根據(jù)權(quán)利要求3所述的方法,其特征在于,所述根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,包括: 每次有待分析方法的返回時(shí)間被記錄到所述指定位置時(shí),判斷該返回的方法是否為所述入口方法; 如果是,則確定一次調(diào)用過程結(jié)束,并對(duì)此次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果進(jìn)行計(jì)算。
7.根據(jù)權(quán)利要求1至6任一項(xiàng)所述的方法,其特征在于,還包括: 從所述指定位置讀取所述待分析方法分別在每次調(diào)用過程中的性能消耗分析結(jié)果并返回。
8.一種獲取程序性能消耗信息的方法,其特征在于,包括: 接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息; 向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令; 觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊,以便通過所述代理模塊執(zhí)行以下步驟:通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ;通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法;在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置;根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置;從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回; 接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn)。
9.一種獲取程序性能消耗信息的裝置,其特征在于,包括: 指令接收單元,用于接收攜帶有待分析目標(biāo)信息的分析指令,所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息; 待分析方法確定單元,用于根據(jù)所述待分析目標(biāo)信息,確定待分析方法; 字節(jié)碼增強(qiáng)單元,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置; 計(jì)算單元,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果。
10.一種獲取程序性能消耗信息的系統(tǒng),其特征在于,包括客戶端模塊及代理模塊,其中: 所述客戶端模塊包括: 信息接收單元,用于接收用戶提交的待分析目標(biāo)信息;所述待分析目標(biāo)信息包括待分析進(jìn)程、待分析方法以及所述待分析方法所屬的類的信息; 指令發(fā)送單元,用于向指定端口發(fā)送攜帶有所述待分析目標(biāo)信息的分析指令; 觸發(fā)單元,用于觸發(fā)所述待分析進(jìn)程對(duì)應(yīng)的Java虛擬機(jī)加載指定的代理模塊; 結(jié)果展現(xiàn)單元,用于接收到所述代理模塊返回的性能消耗分析結(jié)果之后進(jìn)行展現(xiàn); 所述代理模塊包括: 監(jiān)聽單元,用于通過創(chuàng)建Server Socket類監(jiān)聽所述指定端口 ; 待分析方法確定單元,用于通過所述指定端口監(jiān)聽到所述分析指令后,根據(jù)所述待分析目標(biāo)信息,確定待分析方法; 字節(jié)碼增強(qiáng)單元,用于在所述待分析進(jìn)程已加載的類中查找待分析方法的字節(jié)碼,通過字節(jié)碼操縱框架對(duì)所述待分析方法進(jìn)行字節(jié)碼增強(qiáng),以便在待分析方法開始被調(diào)用時(shí)記錄方法開始時(shí)間,將方法開始時(shí)間及方法標(biāo)識(shí)信息保存到指定位置,在待分析方法返回時(shí)記錄方法返回時(shí)間,將方法返回時(shí)間及方法標(biāo)識(shí)信息保存到所述指定位置; 計(jì)算單元,用于根據(jù)所述指定位置記錄的信息,計(jì)算每次調(diào)用過程中涉及的各個(gè)待分析方法的性能消耗分析結(jié)果,并保存到所述指定位置; 返回單元,用于從所述指定位置讀取所述待分析方法的性能消耗分析結(jié)果并返回。
【文檔編號(hào)】G06F9/44GK104346148SQ201310325258
【公開日】2015年2月11日 申請(qǐng)日期:2013年7月30日 優(yōu)先權(quán)日:2013年7月30日
【發(fā)明者】湯鑫斌 申請(qǐng)人:阿里巴巴集團(tuán)控股有限公司