没有合适的资源?快使用搜索试试~ 我知道了~
理论计算机科学电子笔记164(2006)45-64www.elsevier.com/locate/entcs基于字节码指令计数沃尔特·宾德和贾勒·胡拉斯EcolePolytechniqueF′ed′eraledeLausanne(EPFL)School of Computer and Communication SciencesCH-1015 Lausanne,Switzerlandfirstname.lastname@ep.ch摘要本文提出了一种新的分析方法,它完全基于程序转换技术,以实现精确的分析,保留完整的调用堆栈,方法调用计数器和字节码指令计数器。我们利用执行的字节码指令的数量作为profiling度量,这有几个优点,例如使仪器完全可移植和生成可重现的profiles。 这些想法已作为JP工具实施。 它提供了一个小而灵活的API用纯Java编写可移植的profiling代理,定期激活以处理收集的profiling信息。 性能测量指出,JP导致的开销显著低于一个流行的工具,用于精确分析Java代码。关键词:Java,JVM,Profiling,程序转换,字节码插装1介绍Profiling允许对程序的资源消耗进行详细分析。 它有助于检测热点和性能瓶颈,指导开发人员对程序的哪些部分进行优化。Profiling提供了基于单个方法的详细执行统计信息(例如,调用堆栈、调用计数器、CPU时间等)。由于Java [16]和Java虚拟机(JVM)[21]是许多应用程序和中间件开发人员的首选编程语言和部署平台Java Virtual Machine Profiling Interface(JVMPI)[23]是一组指向JVM的钩子,它发出有趣的事件,例如线程启动和对象分配。它的后继者JVM工具接口(JVMTI)[24]为字节码指令提供了额外的便利。许多基于JVMPI或JVMTI的分析器可以在两种模式下运行:在精确分析模式下,它们跟踪每个方法调用,而在采样模式下,分析器花费大部分时间睡眠和周期性地1571-0661 © 2006 Elsevier B. V.在CC BY-NC-ND许可下开放访问。doi:10.1016/j.entcs.2006.07.01146W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45(每隔几毫秒)唤醒以注册当前堆栈跟踪。在本文中,我们专注于精确的轮廓。基于JVMPI或JVMTI接口的profilers实现了profiling代理来拦截各种事件,比如方法调用。不幸的是,这些profiling代理必须用依赖于平台的本机代码编写,这与Java的座右铭“编写一次,在任何地方运行”相矛盾。更有问题的是,基于这样的API进行配置可能会导致巨大的开销。 在精确的配置文件中,程序运行速度通常会慢10倍以上,在极端情况下,我们甚至经历了4000倍以上的减速。因此,基于JVMPI的精确配置不适合复杂的软件系统,如应用服务器,也不可能在生产系统上执行。开发人员花费了大量的精力来提取他们的应用程序的一部分,以单独分析它们,因为由于极端的开销,分析整个系统是不可行的。此外,测量通常会影响分析应用程序的运行时特性,因此获得的执行统计信息的价值有限(测量扰动)。出于这些原因,我们开发了JP,这是一种新的Java profiler,它不依赖于这两个API,而是直接对Java程序的字节码进行检测,以获得详细的执行统计数据。JP插入字节码指令来计算执行配置文件。此外,JP使用执行的字节码1的数量作为分析指标,而不是CPU运行时间。我们的方法具有以下优点:(i) Profiling代理可以用纯Java编写,并且可以更好地与环境集成。因此,profiling代理是可移植的,可以在各种JVM中使用。(ii) profiling代理可以被编程为保留完整调用堆栈的跟踪,或者以一定的间隔压缩它,而现有的profiling代理通常只支持固定的最大堆栈深度。(iii) 执行字节码的数量是一个独立于平台的指标[14]。因此,对于确定性程序,概要文件在不同的机器上是可复制的,也是可比较的(假设使用相同的Java类库)。由JP仪表化的程序生成反映数量的剖面统计数据 字节码,程序将执行没有profiling,即,轮廓本身并不影响生成的轮廓(没有测量扰动)。2(iv) 我们的方法也适用于既不支持JVMPI也不支持JVMTI的JVM,或者对概要文件提供有限支持(v) 与经典方法相比,这种方法的开销相当低,因为它不会阻止底层JVM在profiling期间将其所有优化工具投入工作。本文的主要贡献是详细介绍了程序转换和必要的运行时类,以准确地分析Java程序。1在本文中,术语“字节码”被用作“JVM字节码编译”的同义词。2注意,对于多线程、非确定性程序,分析可能会影响线程调度。W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)4547介绍了纯Java编写的可移植的profiling代理,对使用SPEC JVM98和SPEC JBB2000基准测试进行精确profiling所产生的开销进行了深入的分析,并与 标准的本文的结构如下:第2节介绍了我们的轮廓技术背后的设计原则。第3节介绍了分析器如何管理调用堆栈,以及如何在字节码级别重写应用程序,以生成所需的资料。 第4节解释了我们如何计算数字执行的字节码,作为分析指标。运行时生成的信息由用户定义的profiling agent定期收集,如第5节所述。第6节介绍了我们的性能测量,第7节讨论了我们的方法的好处和局限性,而第8节比较了我们的研究与相关工作。最后,第9节总结了本文。2Java Profiler JP为了克服上述基于JVMPI或JVMTI的profiler的缺点,我们开发了JP,这是一个Java profiler,它既不依赖于这两个API,也不依赖于Java程序的字节码,而是直接检测Java程序的字节码,以获得详细的ex-profiler统计数据。JP插入字节码来计算执行配置文件。目前,JP提供以下资料:(i) 方法调用上下文。对于每个方法调用,都保留完整的调用堆栈。3这允许不同的调用者对同一方法的不同调用。(ii) 方法调用计数器。对于每个方法调用上下文,存储对该方法的调用(iii) 字节码计数器。对于每个方法调用上下文,计算该方法执行与大多数其他profilers不同,它们只保留了有限深度的方法调用上下文,我们保留了完整的调用堆栈,从而能够更详细地分析程序行为。 根据球的术语 和Larus[4],我们遵循路径剖析方法,因为我们维护完整的执行历史(但仅在方法调用级别),而不是更经济和近似的边缘剖析策略。在程序执行期间,每个线程创建方法调用树(MCT),其中每个节点N对应于特定方法的调用。N的父节点是N的调用者,N的子节点是它的被调用者。MCT的根代表main方法的调用者。在每个节点中,我们存储相应方法的调用次数和这些方法调用执行的字节码数量,不包括被调用方方法执行的字节码数量MCT对应于呼叫上下文树(CCT)[2],但与之相反,3目前,如果本机方法的框架在堆栈上,则在保留完整调用堆栈方面存在一些限制。详细讨论见第3.3节。48W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45与CCT相比,MCT的深度是无限的。关于方法调用上下文和方法调用计数的细节在第3节中解释。大多数现有的分析器以秒为单位测量程序的CPU消耗。虽然CPU秒是最常见的性能分析指标,但它有几个缺点:它依赖于平台(对于相同的程序和输入,CPU时间差异取决于硬件、操作系统和JVM),准确地测量它可能需要依赖于平台的功能(例如特殊的操作系统功能),并且结果可能不容易重现(CPU时间可能取决于系统负载等因素)。此外,测量扰动可能是一个严重的问题:当程序在不进行分析的情况下执行时,分析程序的测量CPU消耗可能与有效CPU消耗显著不同。最后一点在JVM上尤其如此,因为JVMPI的使用禁用了即时编译。我们遵循不同的方法,使用字节码计数作为动态度量[6]。也就是说,对于每个方法调用上下文,我们计算未修改的程序将执行的字节码的数量。这些值是平台无关的,它们可以直接从程序字节码中计算,而无需求助于平台特定的函数,它们是可再现的(对于确定性程序),并且它们表示原始程序的执行(没有测量扰动)。在以前的工作中,我们已经建立了字节码计数作为资源核算的平台无关度量(例如,服务器环境的生产时间监视)和控制(例如,防止移动代码系统中的拒绝服务攻击)[10,19,9]。 在这里,该指标是高效配置文件的关键。 关于字节码计数的细节在第4节中介绍。JP是一个灵活的,可扩展的Java框架。它提供了一个API,允许用户定义一个定期激活的自定义配置文件代理。剖析代理可以聚合由若干线程计算的剖析信息。它可以在程序被分析时显示最新的分析信息(连续度量[14]),它可以通过网络发送所获得的信息,或者在程序终止之前将其写入文件。第5节详细讨论了调剖剂和相应API的定期激活。3方法调用上下文和调用计数3.1运行时类在执行转换后的字节码时,每个线程创建一个MCT。树节点是图1所示的IC(调用上下文)类型。每个调用上下文都存储了同一个调用堆栈中某个方法的所有调用的分析信息(方法调用计数器invoc和字节码计数器instr)。4每个调用上下文都有一个被调用方方法的映射。 被调用方方法的标识符(类型MID,见下文)作为映射中的键。 这些值是被调用者的调用上下文。 在图1中,标准的HashMap类是4出于性能原因,invoc和instr计数器是32位值,它们被视为无符号的(参见getInclusive()和getInstr()),以便允许一个超过一个(详细信息将在第5节中解释)。W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)4549public final class RC extends IC {static final ThreadLocal root = new ThreadLocal();public void run(){rec =(rec)rootContext.get();if(rc == null){rc = new RC(); rootContext.set(rc); rc.initialize();} return rc;}...}public class C{ int nums =0;// nr.的方法调用public int strategy = 0;//nr.public final Mapcallees = new HashMap();publicfinallonggetInstrument(){returninvoc0xffffffL;}publicfinallonggetInstr ( ) {returninstr0xffffffL;}publicfinalvoidreset ( ) {instr=invoc=0;}public final IC profileCall(MID mid){ IC ic =(IC)callees.get(mid);if(ic == null){ic = new IC(); callees.put(mid,ic);}++ic.invoc;return ic;}}Fig. 1. 简化IC实现。图二、RC的一部分为了简化表示而使用,而实际实现使用优化的映射,因为对映射的访问非常频繁。为了防止竞争条件,要么访问MCT必须同步,或者每个线程必须维护自己的树副本。为了避免昂贵的同步,并允许profiling代理单独保存不同线程的profiling统计数据,我们选择为系统中的每个线程创建一个单独的MCT。 对于每个线程,其MCT的根存储在线程局部变量5中RC类型(根上下文)。RC实现的一部分在图2中示出。其他部分,如initialize()方法,将在第5节稍后介绍。 静态方法getRC()返回根上下文(IC的实例)对于当前线程。如果它还不存在,它将被创建。方法标识符是MID的实例,MID是一个标记接口(见图3)。出于性能原因,MID的实例直接通过它们的引用来识别和区分。缺省实现MIDImpl保留类名、方法名和方法签名。它不保留对类的引用,以免阻止垃圾回收器回收该类。然而,用户可以用系统属性org.jp.MIDFactory指定定制MIDFactory实现(参见图3),以便使用不同的MID实现(例如,以保存关于类加载器的信息等)。5线程局部变量是java.lang.ThreadLocal的实例。 每个线程都有自己的线程局部变量实例。在内部,线程局部变量由与每个Thread对象关联的映射实现。50W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45public interface MID {}//方法标识符publicfinal class MIDImpl implements MID {final String clName,mName;public MIDImpl(Class c,String mns){clName = c.getName(); mNameSig =mns;} public String getClassName(){ return clName;}public String getMethodNameSig(){return mNameSig;}}public interfacesMIDFactory {public String getString(String s);}public final class MIDFactoryImpl实现MIDFactory { staticMIDFactory midf;static{ try{String f = System.getProperty(“org.jp.MIDFactory”); midf =(f == null)?newMIDFactoryImpl():(MIDFactory)Class.forName(f).newInstance();}public int findDuplicate(1);}}public static MID getMID_0(Class c,String mns){return midf.getMID(c,mns);} public MID getMID(Class c,String mns){return new MIDImpl(c,mns);}}图三. MID、MIDImpl、MIDFactory和MIDFactoryImpl3.2重写方案我们重写JVM字节码,以便将调用方的IC对象作为额外的参数传递给被调用方方法(即,我们用类型为IC的参数扩展所有非原生方法的签名)。在每个方法的开始,被调用方对接收到的IC对象调用profileCall(MID),以便获得其自己的(即,被呼叫者profileCall(MID)根据被调用方的MID查找被调用方如果存在(即, 同一被呼叫者已经 如果在调用之前被调用),则调用计数器递增并且返回IC对象。否则,分配一个新的IC实例,插入到map中(使用方法标识符作为键),并返回。由于重写不会改变本机代码,因此我们添加了简单的包装方法,这些方法具有未修改的签名,通过调用静态方法RC.getRC()获得当前线程因此,本机代码能够使用未修改的签名调用Java方法6为每个方法,我们添加一静态菲尔德到举行的对应-ingMID实例。在静态初始化器中,我们调用静态方法MIDFactoryImpl.getMID0(Class,String)(见图3),以便为每个方法分配一个MID实例。 如果没有自定义MIDFactory实现, 如果指定了,则返回MIDImpl图4中的示例说明了这种变换方案。左边是重写前的Foo类,有方法f()、g(int)和h(),右边是重写后的版本。7如果重写的f()方法被调用一次,它将6对于我们无法重写的原生方法,我们添加了所谓的“反向”包装器,在调用原生方法之前丢弃额外的IC参数。“反向”包装器允许重写的代码调用带有附加参数的所有方法,无论被调用者是否是本机的7为了更好的可读性,在本文中,我们展示了Java代码上的所有转换,而JPW. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)4551Σi=11=2class Foo {class Foo {private static final MID mid_f,mid_g,mid_h;静态{Class c = Class.forName(“Foo”);mid_f = MIDFactoryImpl.getMID_0(c,“f()V”);mid_g = MIDFactoryImpl.getMID_0(c,“g(I)V”);mid_h = MIDFactoryImpl.getMID_0(c,“h()V”);}public int findDuplicate(int findDuplicate){int i= 1;i = 10;++i){inti=1; i = 10;++i){public int findDuplicate();(i,i,c);} }个文件夹} }个文件夹public void findDuplicate(){findDuplicate();}public int findDuplicate(int findDuplicate){int n = int n(int n);for(int j=1;j =i;++j)for(int j=1;j =i;++j)public int findDuplicate();} }个文件夹public int findDuplicate(int i){int i(int i);}public void run(){int i = int i. int i(i);} }个文件夹public void online(){online()}} }个文件夹见图4。 重写示例:MCT创建。计算以下配置信息:f = 1,f. h = 10,f.g = 10,f. g. h = 55。也就是说,f()被调用了一次,h()和g(int)被f()调用了10次,并且h()w被yg(int)计算55次。Σ10ij=110i=1 i= 11 10= 55。3.3本机代码问题和JDK类每当本机代码调用重写的Java方法时,它将调用具有未修改签名的包装器方法。 也就是说,调用者的调用上下文是 不传递,因此丢失了有关调用堆栈的信息。包装器方法将获取根上下文并将其用作调用方的调用上下文。因此,本机代码调用的所有方法将在MCT中显示为根上下文的子节点,即,作为main方法的兄弟有一些方法可以在包装器方法中(部分)恢复调用堆栈:例如,可以利用ThrowableAPI来获取堆栈跟踪。 然而,这种方法并不是完全可移植的,因为ThrowableAPI允许JVM实现者有很多可移植性(例如,堆栈跟踪在某些JVM上可能不完整)。此外,堆栈跟踪元素不提供被调用方法的签名。为了避免歧义,重写工具必须重命名重载方法(具有相同名称但不同签名的同一类的方法),例如,通过在方法名中编码签名。但是,这种方法不能用于重载构造函数(它们的名称不能更改)。工作在JVM字节码级别。52W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45由于这些困难,JP目前只支持之前提出的方案,其中本机代码对重写方法的所有调用都显示为根上下文的子项。因为从本机代码到重写的Java代码的这些回调并不频繁,所以这种不精确性在实践中不会引起太多问题另一个问题是当前JP没有为本地方法创建任何调用上下文。原则上,本机方法的“反向”包装器可以注册被调用方的调用上下文。然而,即使使用这种方案,我们也无法跟踪其他本机方法调用的本机方法的调用。为了描述Java开发工具包(JDK)提供的Java方法的执行,JDK类也必须重写。 在以前的工作中,我们已经解释了修改标准JDK类的困难[8]。例如,如果JDK被重写,类RC不能依赖于线程局部变量,但Thread类必须扩展一个包含对线程根上下文的引用的字段。当我们解决了JDK重写的困难,与以前的工作[8]一样,我们在这里不重复这些细节4字节码计数JP提供了精确的执行统计数据:对于每个方法调用上下文,它计算执行的字节码数量,这可以作为平台无关的分析指标。执行的字节码的数量存储在IC实例的instr字段中(见图1)。①的人。JP检测方法的字节码,以便根据执行的字节码数量增加instr计数器。8对于每个Java方法,JP执行基本块分析(BBA)以计算控制流程图。在每个基本块的开头,它插入一个代码序列,该代码序列使instr计数器递增基本块中的字节码数BBA算法在JP中没有硬编码,用户可以通过系统属性指定自定义分析算法。JP本身有两个内置的BBA算法,我们分别称之为“默认BBA”。“精准BBA”。在“默认BBA”中跳转、分支、方法或JVM子例程返回、异常抛出)结束基本块。方法、构造函数或JVM子例程调用不会结束基本代码块,因为我们假设执行将在调用后返回。基本块的这个定义对应于[10]中使用的定义“Default BBA”的优点是它创建了相当大的基本块。因此,减少了必须插入对instr计数器的更新的位置的数量,从而降低了配置开销。只要没有抛出异常,生成的分析信息就是精确的。然而,例外情况(例如,一个被调用的方法可能会异常地终止,抛出一个异常),这可能会导致会计中的一些(轻微的)不精确,因为我们总是计算基本块中的所有字节码,即使它们中的一些在异常的情况下可能不会被执行8由于instr字段由于性能原因而直接递增,因此在 图1.一、W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)4553public void run(){int i = 1;while(true){if(i = 10){i();(i);++i;}否则{返回;}}}public int findDuplicate(intfindDuplicate){c = c.profileCall(mid_f);c.instr += 2;int i = 1;while(true){if(i = 10){ic.instr +=7; h(ic);i(i,i);++i;}否则{int i = 1;return;}}}public void findDuplicate(){findDuplicate();}图五.重写示例:字节码计数。也就是说,使用“默认BBA”,我们可以计算比执行更多的如果用户想要避免这种潜在的不精确性,他可以选择“精确BBA”,其在每个字节码之后结束基本块,其可以非顺序地改变控制流(如前所述),或者可以抛出异常。因为有许多字节码可能抛出异常(例如,NullPointerException可能会被大多数需要对象引用的字节码引发),因此产生的平均基本块大小非常小(在我们检查的代码示例中,大多数块的大小都在1到4之间)。这不可避免地导致了字节码计数的更高开销,因为每个基本块都由JP进行检测。在第6节中,我们将比较“默认BBA”和“精确BBA”的性能图5中的重写示例示出了在每个基本块的开始处插入代码以便计算执行的字节码的数量。9在本例中,我们应用了其中只有可能改变控制流的字节码非顺序地结束基本块。例如,if()语句中的基本块由7个字节码组成:将this引用加载到堆栈上,调用h(),将this引用加载到堆栈上,将i的值加载到堆栈上,调用g(int),递增 如果是i,则跳转到循环的开头。 如果使用“精确BBA”,if()语句中的3个块(因此对instr计数器进行了3次更新),因为h()和g(int)的调用都将结束一个基本块。5定期激活自定义配置文件代理5.1促性腺激素JP支持用户定义的profiling代理,每个线程定期调用这些代理,以聚合和处理线程收集的profiling信息。自定义profiling代理必须实现所示的Profiler接口图5中左侧的方法f()对应于图4中左侧的方法f()。 我们用一个等价的while()结构替换了for()循环,以便更好地显示编译后字节码的基本块结构。标准的Java编译器将两种版本的方法f()转换为完全相同的JVM字节码序列。54W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45−public final class RC extends IC {...public intactivationCounter;public void onlineReport(IC currentIC){ activationCounter = profiler.report(this,currentIC);}public void run(){System. out. println();}...}public interface Profiler {public int register(Thread t,RC rc);public int report(RC rc,ICcurrentIC);}见图6。 Profiler接口。见图7。 RC的一部分。在图6中。 当一个新线程开始执行时,它首先创建它的根上下文,然后调用profiling agent的register(Thread,RC)方法。静态方法RC.getRC()(参见图2)在调用图7中给出的initialize()方法之前将新的根上下文存储在线程局部变量中,该方法进而向profiling代理注册新线程及其根上下文在执行过程中,每个线程周期性地调用分析代理的report(RC,IC)方法。此方法接收调用线程的根上下文和当前执行上下文。 从根上下文开始,可以遍历调用线程的MCT,将其集成到其状态中。当前的experimentcontext告诉profiling代理调用线程当前执行的是哪个方法。分析代理的register(Thread,RC)和report(RC,IC)方法返回的值调用线程在再次调用report(RC,IC)之前要执行的字节码的近似数量。 分析代理可以在每次调用报告(RC,IC)时改变分析粒度,并且可以将不同的分析粒度应用于每个线程。周期性激活允许剖析代理在整个程序执行期间处理所收集的剖析信息,这对于显示长时间运行的程序(诸如应用服务器)的最新剖析信息特别有用。此外,分析代理的周期性调度保证了invoc和instr计数器的全部范围(见图1), 32位值,不超过。由于配置粒度被限制为231 1(最大值),因此invoc和instr计数器最多可以溢出一次。最终的overflow由IC的getInclusion()和getInstr()方法处理,它们将这些变量视为无符号值(参见图1)。在将调用线程的MCT集成到其状态中之后,分析代理必须重置Invoc和Instr计数器为零。对MCT的访问不需要同步,因为report(RC,IC)方法由拥有MCT的线程同步调用。W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45555.2重写方案为了调度自定义分析代理的定期激活,每个线程都维护自上次调用report(RC,IC)方法以来执行的字节码数量的上限。该值保存在每个线程根上下文的activationCounter字段中。 为了让每个方法都可以访问这个计数器(而不需要调用线程局部变量,这会导致很高的开销),我们将根上下文作为一个额外的参数传递给所有非原生方法/构造函数的调用。如果activationCounter达到或超过了当前的profiling粒度,线程就会调用Profiling Report(IC),这又会调用profiling agent(参见图7)。请注意,activationCounter的值不是profiling统计信息的一部分,它仅在运行时用于确保定期激活profiling代理。作为一种优化,activationCounter的值从当前的profiling粒度向下运行到零,因为有专用的字节码用于与零进行比较。下面的条件用于安排profiling agent的定期激活:if(rc.activationCounter = 0);activationCounter以与instr计数器递增类似的方式递减(参见第4节)。然 而 , 为 了 减 少 开 销 , 我 们 不 会 在 每 个 基 本 代 码 块 的 开 头 递 减 它 :activationCounter在每个方法,异常处理程序和JVM子例程的开头更新,以及在每个循环的开始。每次都按最长执行路径上的字节码数递减,直到下一次更新或方法终止。这确保了activationCounter的值表示执行字节码数量的上限在每个方法的开头和每个循环中插入检查是否必须调用ClerReport(IC)的条件,以确保它出现在递归和迭代中。 作为一种优化,我们省略了条件在一个方法的开始,如果在调用任何方法/构造函数之前,每个执行路径要么终止,要么通过一个插入的条件传递。例如,这种优化允许删除叶方法开头的检查。图8中的示例说明了JP完成的完全重写:每个方法接收两个额外的参数,根上下文和调用者activationCounter在方法的开始和循环中更新。 在下一次更新或方法终止之前,它将按最长执行路径上的字节码数递减。例如,在循环中,它被递减10(3+ 7),因为如果循环被重复,这是执行路径的长度。另一条路径返回,只执行4个字节码(3+ 1)。条件存在于循环中,但不存在于方法的开头,因为56W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45publicvoid run(){int i = 1;while(true){if(i = 10){return();(i);++i;}否则{返回;}}}public int findDuplicate(intfindDuplicate){c = c.profileCall(mid_f);rc.activationCounter -= 2;public intfindDuplicate(){return 10;if(rc.activationCounter =0);if(i = 10){ic.instr +=7; h(rc,ic);g(i,rc,ic);++i;}否则{int i = 1;return;}}}public void run(){C = C. getC(); f}图8.第八条。重写示例:定期激活profiling agent。在调用任何方法之前,只有可能的执行路径经过循环中的条件。5.3加载自定义配置文件代理如果JDK类被重写以进行分析,那么重要的是不要扰乱JVM加载其核心类的顺序。由于自定义profiling agent可能会利用任意的JDK类,因此将其加载和实例化延迟到JVM的引导完成之后是至关重要的。由于我们在以前的工作中描述了一个类似问题的解决方案,即修改后的JDK的自举[19],我们不会重复本文中的细节。我们假设静态变量RC.profiler(见图7)在引导后被设置为保存对自定义profiling agent的引用。与用户定义的profiling agent(在JVM完成引导后加载)相反,类IC和RC以及MID和MIDFactory的实现(见图3)(可以定制)在JVM引导过程中很早就加载了。因此,它们不应该依赖于其他类(除了核心类,如String,Class等)。例如,它们不能使用Java实用程序包中的类,如集合。profiling代理的提供者可以依赖MIDImpl,MID的默认实现(见图3),或者提供他自己的MID和MIDFactory实现。在后一种情况下,他必须非常小心,不要使用可能会破坏JVM引导的helper类。5.4亲化剂在下文中,我们绘制了一个简单的仿形剂(SPA)的结构,我们在第6节中使用的性能测量。由于空间限制,W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)4557我们不显示程序代码,但只总结了有趣的实现方面。SPA的使用方式类似于许多JDK中包含的标准profilers,例如由' -prof ',' -Xrunhprof '或' -agentlib:hprof '(后者自JDK 1.5.0起)命令行选项调用的那些现有的工具,如prophIt10,可用于可视化输出。SPA实现Profiler接口,并依赖于MID的默认实现。它为所有线程维护一个全局MCT(GMCT)。 在GMCT中,调用和字节码计数器是64位值(即,过流不是问题)。所有SPA操作,如寄存器(线程,RC)和报告(RC,IC),都是同步的,以确保GMCT的一致性每当线程调用SPA对于已经存在于GMCT中的节点,调用和字节码计数器相应地递增,否则创建新节点。在将调用线程的profiling信息传输到GMCT中时为 了 收 集 已 终 止 线 程 的 分 析 信 息 , SPA 保 留弱 引 用 ( 即 ,java.lang.ref.WeakReference的实例)到每个注册的线程。弱引用不会阻止线程对象被垃圾回收器回收。当弱引用引用的线程对象被垃圾回收时(这意味着线程已终止),弱引用将在引用队列中排队。SPA跟踪对已注册线程的弱引用,并维护对相应RC实例的引用。SPA使用一个专用的高优先级守护进程线程,该线程等待弱引用在引用队列中排队。如果发生这种情况,守护进程线程将终止线程的MCT复制SPA使用了一个shutdown hook,一个在JVM即将终止时开始运行的专用线程,即,当程序正常退出时(最后一个非守护进程线程已终止或System.exit(int)被调用),或者当JVM响应用户中断而终止时。shutdown hook将收集到的配置文件信息(即,GMCT)文件。6评价为了评估我们的性能分析方案引起的开销,我们使用了SPEC JVM98基准测试套件11(问题大小100),它由7个基准测试组成,以及SPEC JBB2000基准测试套件12(仓库序列1、2、3、4、5、6、7、8) Linux Fedora Core 2计算机(Intel Pentium4,2.66 GHz,512 MB RAM)。大都会-第10http://prophit.westslopesoftware.com/第11http://www.spec.org/osg/jvm98/12http://www.spec.org/osg/jbb2000/58W. Binder,J.Hulaas/Electronic Notes in Theoretical Computer Science 164(2006)45.resp.- 是的把我们的预处理器和一个-执行时间(无配置文件)1 101001000621.72100001101001000804.7310000110100 10001000021.45压缩2.45
下载后可阅读完整内容,剩余1页未读,立即下载
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![-](https://csdnimg.cn/download_wenku/file_type_lunwen.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/default.jpg!1)
cpongm
- 粉丝: 4
- 资源: 2万+
上传资源 快速赚钱
我的内容管理 收起
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
会员权益专享
最新资源
- 京瓷TASKalfa系列维修手册:安全与操作指南
- 小波变换在视频压缩中的应用
- Microsoft OfficeXP详解:WordXP、ExcelXP和PowerPointXP
- 雀巢在线媒介投放策划:门户网站与广告效果分析
- 用友NC-V56供应链功能升级详解(84页)
- 计算机病毒与防御策略探索
- 企业网NAT技术实践:2022年部署互联网出口策略
- 软件测试面试必备:概念、原则与常见问题解析
- 2022年Windows IIS服务器内外网配置详解与Serv-U FTP服务器安装
- 中国联通:企业级ICT转型与创新实践
- C#图形图像编程深入解析:GDI+与多媒体应用
- Xilinx AXI Interconnect v2.1用户指南
- DIY编程电缆全攻略:接口类型与自制指南
- 电脑维护与硬盘数据恢复指南
- 计算机网络技术专业剖析:人才培养与改革
- 量化多因子指数增强策略:微观视角的实证分析
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)