现在的位置: 首页 > 综合 > 正文

如何从jar包中检索特定规则的代码

2013年01月02日 ⁄ 综合 ⁄ 共 3322字 ⁄ 字号 评论关闭

欢迎转载,转载请注明来源: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规则,然后扫描,是行的通的。

【上篇】
【下篇】

抱歉!评论已关闭.