如何從jar包中檢索特定規則的代碼

歡迎轉載,轉載請註明來源:http://blog.csdn.net/lywybo/article/details/8774116


這樣一種情況:

現在生產環境中避免工程師誤用System.gc(),大部分企業級java應用都會把程序中System.gc()的調用禁止掉。

禁用方法:調整jvm參數-XX:+DisableExplicitGC 

禁用之後避免人爲造成系統的full gc影響生產環境的性能。禁用之後不但代碼中的System.gc()被禁用,jar包中的System.gc()也被禁用了。


最近生產環境遇到的一個問題:

某天在系統壓力、併發很小、但是單用戶訪問很頻繁的情況下服務器掛掉了,報

java.lang.OutOfMemoryError: Direct buffer memory  
    at java.nio.Bits.reserveMemory(Bits.java:633)  
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:98)  
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288) 

爲啥會出現這個問題呢?等我下篇問章在說,反正就是因爲,禁用了System.gc(),然後某些jar必須通過這種方式來釋放,於是乎就出現這個錯誤。


如何解決:

考慮把System.gc()給打開,但是打開會帶來多大的影響呢?不知道,因爲我們不清楚系統依賴的jar包中有多少個jar用到了System.gc(),於是乎其他團隊的童鞋來求助我,有麼有什麼辦法能找出來,系統依賴的jar中哪些用到了gc。

當然最簡單的方法,一個一個jar去找。。。明顯不靠譜,哈哈

因爲jar大多數是class文件,字節碼,於是我就想到了findbugs。寫一條專門找System.gc()的規則,然後建立一個ant任務直接掃描系統的lib目錄,不就可以實現了麼?

想到就動手,首先寫gc的規則,規則開發參考:http://blog.csdn.net/lywybo/article/details/5335748

/**
 * 這個規則類主要用於檢查代碼中是否有System.gc這樣的輸出語句
 * 
 * @author yuezhen
 * @version $Id: AlipayForbiddenSystemClass.java,v 0.1 2013-04-08 下午05:12:43
 *          yuezhen Exp $
 */
public class AlipayForbiddenSystemGcClass extends OpcodeStackDetector {

	private final BugReporter bugReporter;

	private static final String SYSTEMFLG = "java/lang/System";

	private static final String GC = "gc";

	/**
	 * @param bugReporter
	 */
	public AlipayForbiddenSystemGcClass(BugReporter bugReporter) {
		this.bugReporter = bugReporter;
	}

	/**
	 * visit方法,在每次進入字節碼方法的時候調用 在每次進入新方法的時候清空標誌位
	 */
	@Override
	public void visit(Code obj) {
		super.visit(obj);
	}

	/**
	 * 每掃描一條字節碼就會進入sawOpcode方法
	 * 
	 * @param seen
	 *            字節碼的枚舉值
	 */
	@Override
	public void sawOpcode(int seen) {
		if (seen == INVOKESTATIC) {
			// 判斷是否爲SYSTEMFLG類型,並且使用了GV方法
			if (getClassConstantOperand().equals(SYSTEMFLG) && getNameConstantOperand().equals(GC)) {
				BugInstance bug = new BugInstance(this, "ALP_ALIPAY_SYSTEM_GC_CLASS", HIGH_PRIORITY).addClassAndMethod(this)
				        .addSourceLine(this, getPC());
				bug.addInt(getPC());
				bugReporter.reportBug(bug);
			}
		}
	}
}

悲催的是,寫好規則之後,測試時候發現,原來findbugs默認已經有這條規則了。。。。我了個汗。不過複習了一遍規則的開發。

既然有規則了,那麼要做的就簡單了,只需要寫個ant任務,來掃描即可。並且我們需要設置只掃描GC那條規則。否則規則太多影響分析。

<project name="scan">
	        <property name ="findbugs.path" value ="/home/admin/findbugs/findbugs-1.3.9/lib" />          
                <property name ="findbugs.result" value ="/home/admin/findbug" /> 
                <property name ="findbugs.scan.path" value ="/home/admin/....項目lib路徑.../lib/" />     
                <property name ="findbugs.include.filter" value ="/home/admin/findbugs/rule.xml" />       
                <path id ="findbug.path" >                  
                        <fileset dir ="${findbugs.path}" >          
                             <include name ="*.jar" />                  
                        </fileset >                  
                </path >          
                <!--定義findBugs任務 -->         
                <taskdef name ="findbugs" classpathref ="findbug.path"  classname ="edu.umd.cs.findbugs.anttask.FindBugsTask" />          
               
                         
                <target name ="findbug" >                  
                        <delete dir ="${findbugs.result}" />          
                        <mkdir dir ="${findbugs.result}" />          
                        <findbugs home ="${findbugs.path}" output ="html"  outputFile ="${findbugs.result}/bug.html" jvmargs ="-Xmx1500m" timeout ="6000000" includeFilter="${findbugs.include.filter}" >
                            <!-- 掃描的class、jar路徑 -->
                            <class location ="${findbugs.scan.path}/" />      

                            <!-- 依賴的jar路徑,findbugs掃描過程中 -->          
			                <auxClasspath>                  
                                <fileset dir ="${findbugs.scan.path}" >          
                                      <include name ="*.jar" />                  
                                 </fileset >         
                            </auxClasspath >           
                        </findbugs >                  
                </target >      
</project>

下面來一個findbugs的過濾器,來保證只掃描gc規則,規則詳解參考:http://hulongzhou.blog.hexun.com/33024717_d.html

<FindBugsFilter>
	<Match>
        <BugCode  name ="Dm"/>
	 	<Bug pattern="DM_GC" />
     </Match>
</FindBugsFilter>    

於是乎,規則寫好了,直接運行之,看報告,很清楚的可以知道,如下幾個jar用到了gc



----------------------------------------------分割線----------------------------------------------------------


其實這提供了一種思路,如果想查找jar中某些特定規則的代碼,其實通過寫findbugs規則,然後掃描,是行的通的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章