- 浏览: 3049552 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
今天开始Sun的老blog真的搬迁了,从blogs.sun.com迁移到blogs.oracle.com。结果这些迁移了的blog里的老帖像洪水般一下就把我的reader冲爆了。
不过也好,有些老帖过了一段时间重新读也会有新体会。例如这篇,Why won't JRockit find my classes
原帖里提到这样一种情况。假如在一个路径“foo”里有下面的Foo类对应的Foo.class文件:
然后在“当前目录”下有下面的ClasspathTest类对应的Classpath.class文件:
那么用JRockit直接在当前目录运行ClasspathTest会遇到NoClassDefFoundError:
别人帖里的例子自己都验证一遍是个好习惯。这里我们实际运行JRockit R28确实看到跟描述一样的异常了。
原文同时也提到同一个程序用Oracle/Sun JDK的HotSpot VM来跑就没问题:
原文说,造成这个差异的原因是HotSpot VM有解释器,执行一个方法并不需要事先将该方法中所有类都加载,而可以一点点执行,到方法中间碰到某个未加载的类的时候再去加载它。例子中的代码做了件很tricky的事情:改变了系统类加载器可访问到的路径。等到HotSpot VM的解释器尝试用系统类加载器去加载Foo的时候,Foo.class已经在它能找到的路径上了。
而JRockit则不同,没有解释器,所有Java方法都必须先JIT编译了才可以开始执行。其中有个实现细节,就是JRockit要求在编译某个方法的时候就保证其中涉及的类型都加载好了。但是,上面的例子里,当JRockit的JIT编译器尝试用系统类加载器去加载Foo的时候,该类加载器还没得到“foo”这个路径,所以Foo类就加载不到了。
当然并不是说只有JIT编译器而没有解释器的设计就一定会导致这种结果,只是JRockit选择了这样实现而已。
======================================================
那么HotSpot VM里能否制造出同样的情况呢?我们知道,HotSpot VM可以通过-Xcomp,或者诸如-XX:+UseCompiler -XX:-UseInterpreter -XX:-BackgroundCompilation这样的参数强行指定(尽量)不使用解释器而(尽量)只用JIT编译器来处理Java程序的执行。
在这种条件下HotSpot VM会不会也跟JRockit一样,执行上面的例子报错说找不到类呢?
让我们试试看。下面的例子都是在32位Windows XP上用JDK 6 update 25跑的:
嗯?没报错。
那有没有可能是HotSpot VM实际上没编译ClasspathTest.main()方法呢?用-XX:+PrintCompilation来看:
有的,这个main()方法编译了。
但是,HotSpot的server编译器到底给main()方法生成了怎样的代码呢?用-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly来看:(用法参考以前一帖)
可以看到,生成的代码只做了这么几件事情:
1、检查调用栈是否要溢出了(0x00a33b00)
2、保存老栈帧信息,建立新栈帧(0x00a33b07-0x00a33b08)
3、?(0x00a33b0e)
4、不应该跑到这里来,否则中断(0x00a33b18)
这问号就是有趣的地方了。如果这个问号表示的代码不足以执行main()的内容的话,那main()到底是如何被执行的呢?
我们可以用另一组参数来了解这神秘的“0x0099c700”地址到底是什么东西,-XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode
嗯,很长很诡异的代码对吧?实际上这块代码是一个“uncommon trap”,也就是当HotSpot的server编译器遇到它觉得不会发生的、或不方便处理的部分的时候会用到的一块代码。
前面提到的“问号”的代码,就是用于跳进该“uncommon trap”的。
但main()方法为啥刚一进去就要无条件跳进一个uncommon trap呢?这次我们换用一个fastdebug版的JDK 6 update 25,然后用-XX:+PrintOptoAssembly来看看:
代码里嵌着的注释说得很明白了,跳进uncommon trap的原因是“unloaded”,也就是该方法需要用的类要么尚未加载,要么虽然加载过但已经卸载掉了。相应采取的措施就是“reinterpret”,也就是退回到解释器去执行。
具体做检查的代码在这里:
也就是HotSpot的JIT编译器做初步类型分析的时候就已经发现有问题了。
看到了么?HotSpot的server编译器只是等同于给例子里的main()生成了个解释器入口,让它跳进去而已,并没有真的把main()方法编译出来。
所以说HotSpot的server编译器其实跟JRockit的JIT编译器在这点上都偷懒了…
只不过HotSpot能退回到解释器里,所以编译器偷懒了没关系,程序还能跑,就是慢一些;JRockit的编译器偷懒了,Java程序搞不好就得撞墙了
HotSpot的client编译器在遇到编译时仍未resolve的符号的话,会在使用这些符号的位置生成一个call thunk,调用一个用于符号解析的thunk,解析好之后把直接引用patch回到原本的call thunk上。这样不用只为解决符号引用的resolution就掉回到解释器里,但生成的代码质量也会稍微差一些。
P.S. 顺带一提:HotSpot的server编译器并不会在接受某个方法的编译请求时强制要求里面涉及的所有类型已经被加载,只要求在方法签名里出现的类型在编译前已经被加载,并要求在编译前该方法里涉及的所有的字符串常量已经resolve完(具体执行这些约束的时负责分派编译请求的CompilerBroker而不是server编译器自身,见回复里的讨论)。
所以这个例子就算给了-classpath ".;foo"也会得到一样的、只含一个uncommon trap的main()方法。
P.P.S. 顺带找个地方记下ciTypeFlow的作用:
http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2008-May.txt
在jvm spec 2.17.2 中
"The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError will be thrown at any point in the program that (directly or indirectly) uses the type:"
而且下面列出NoClassDefFoundError是loading的error,那它应该在用到该类型的时候抛出。在这个例子中,main方法执行的入口时候并没有用到Foo,只有在new Foo的时候用到,jrockit的做法相当于prefetch或者group loading,但jvm有责任确保不应该因为这个引起额外的异常,(这里有点绕,我理解是如果有异常,那不使用prefetch or group loading的classloader也会报错)
这个例子里使用反射不知道是不是很重要,URLClassLoader的addUrl方法是protected的,自定义classloader就可以绕过它。但不知道是不是因为用了反射才会出现这个结果。
前面的解释都说得通。但我觉得问题点在于system class loader到底是个什么类型的对象,在JVM规范里没定义,所以本来Java应用不应该能够假定它会是URLClassLoader的子类的实例。这样的话,依赖该class loader有addURL方法、并且通过它修改class path的做法的结果会怎样本来就应该也是未定义的吧。
刚试着搜了一下,在JVM规范里没找到"system class loader"的定义。这玩儿是在哪里定义的呢?
能详细说说这一点吗,我印象中CompilerBroker只是发起请求,tiered compilation时为什么compiled code要和它打交道。
在jvm spec 2.17.2 中
"The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError will be thrown at any point in the program that (directly or indirectly) uses the type:"
而且下面列出NoClassDefFoundError是loading的error,那它应该在用到该类型的时候抛出。在这个例子中,main方法执行的入口时候并没有用到Foo,只有在new Foo的时候用到,jrockit的做法相当于prefetch或者group loading,但jvm有责任确保不应该因为这个引起额外的异常,(这里有点绕,我理解是如果有异常,那不使用prefetch or group loading的classloader也会报错)
这个例子里使用反射不知道是不是很重要,URLClassLoader的addUrl方法是protected的,自定义classloader就可以绕过它。但不知道是不是因为用了反射才会出现这个结果。
嗯,CompilerBroker名字都已经这么叫了,也就是个转发者的角色。如果说它是解释器与JIT编译器之间的接口上的东西也对,那么两边都算不上。但CompilerBroker在tiered compilation里多数时候都在跟compiled code打交道,从compiled code里跟compiler打交道算不算是整个compilation system的一部分就模糊了。
不过你说得对,我应该把正文的最后那段改改,强调只是个约束而不是opto主动发起的动作。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
如果不是-Xcomp的话,以默认的mixed mode是不应该遇到方法签名上有未加载的类型的。就这点而言在HotSpot上跑的一般Java程序是不会遇到帖子里说的问题的。
话说回来,原本为啥会弄CTW模式来测试HotSpot的编译器的…CTW也确实就是只“为了做测试”而存在的模式,而那个模式下会出现很多奇怪的情况,跟-Xcomp有相似之处
嗯,compiler thread是不会调用Java-level方法的。不过前面也一直没说过那些加载动作是在compiler thread上做的吧…是怎么掉进这段对话的orz
值不值得深入要看目的了。如果关注opto里的很多奇怪的约束,免得改代码的时候不小心弄坏的话,那各种细节都不得不留意。除此之外的话…
印象中hotspot的compiler不负责加载任何java类,加载类需要执行类的<clinit>方法,compiler thread是不会执行任何java方法的,所以应该还是java thread来加载类。
可以看看CompilerBroker的实现。脏活累活opto都交给别人干了 XD
hotspot/src/share/vm/compiler/compileBroker.cpp
印象中hotspot的compiler不负责加载任何java类,加载类需要执行类的<clinit>方法,compiler thread是不会执行任何java方法的,所以应该还是java thread来加载类。
不过也好,有些老帖过了一段时间重新读也会有新体会。例如这篇,Why won't JRockit find my classes
原帖里提到这样一种情况。假如在一个路径“foo”里有下面的Foo类对应的Foo.class文件:
Mattis Castergren 写道
public class Foo { public Foo () { System.out.println("Foo created"); } }
然后在“当前目录”下有下面的ClasspathTest类对应的Classpath.class文件:
Mattis Castergren 写道
import java.io.File; import java.net.URLClassLoader; import java.net.URL; import java.lang.reflect.Method; public class ClasspathTest { private static final Class[] parameters = new Class[]{URL.class}; // Adds a URL to the classpath (by some dubious means) // method.setAccessible(true) is not the trademark of good code public static void addURL(URL u) throws Exception { Method method = URLClassLoader.class.getDeclaredMethod("addURL", parameters); method.setAccessible(true); method.invoke((URLClassLoader) ClassLoader.getSystemClassLoader(), new Object[]{u}); } public static void main(String[] arg) throws Exception{ // Add foo to the classpath, then create a Foo object addURL(new File("foo").toURL()); Foo a = new Foo(); } }
那么用JRockit直接在当前目录运行ClasspathTest会遇到NoClassDefFoundError:
D:\test\test_hotspot_compilers\test_c2_Xcomp_classpath>C:\sdk\Java\jrmc-4.0.0-1.6.0\bin\java ClasspathTest Exception in thread "Main Thread" java.lang.NoClassDefFoundError: Foo at ClasspathTest.main(ClasspathTest.java:20)
别人帖里的例子自己都验证一遍是个好习惯。这里我们实际运行JRockit R28确实看到跟描述一样的异常了。
原文同时也提到同一个程序用Oracle/Sun JDK的HotSpot VM来跑就没问题:
D:\test\test_hotspot_compilers\test_c2_Xcomp_classpath>D:\sdk\jdk1.6.0_25\bin\java ClasspathTest Foo created
原文说,造成这个差异的原因是HotSpot VM有解释器,执行一个方法并不需要事先将该方法中所有类都加载,而可以一点点执行,到方法中间碰到某个未加载的类的时候再去加载它。例子中的代码做了件很tricky的事情:改变了系统类加载器可访问到的路径。等到HotSpot VM的解释器尝试用系统类加载器去加载Foo的时候,Foo.class已经在它能找到的路径上了。
而JRockit则不同,没有解释器,所有Java方法都必须先JIT编译了才可以开始执行。其中有个实现细节,就是JRockit要求在编译某个方法的时候就保证其中涉及的类型都加载好了。但是,上面的例子里,当JRockit的JIT编译器尝试用系统类加载器去加载Foo的时候,该类加载器还没得到“foo”这个路径,所以Foo类就加载不到了。
当然并不是说只有JIT编译器而没有解释器的设计就一定会导致这种结果,只是JRockit选择了这样实现而已。
======================================================
那么HotSpot VM里能否制造出同样的情况呢?我们知道,HotSpot VM可以通过-Xcomp,或者诸如-XX:+UseCompiler -XX:-UseInterpreter -XX:-BackgroundCompilation这样的参数强行指定(尽量)不使用解释器而(尽量)只用JIT编译器来处理Java程序的执行。
在这种条件下HotSpot VM会不会也跟JRockit一样,执行上面的例子报错说找不到类呢?
让我们试试看。下面的例子都是在32位Windows XP上用JDK 6 update 25跑的:
D:\test\test_hotspot_compilers\test_c2_Xcomp_classpath>D:\sdk\jdk1.6.0_25\bin\java -server -Xcomp ClasspathTest Foo created
嗯?没报错。
那有没有可能是HotSpot VM实际上没编译ClasspathTest.main()方法呢?用-XX:+PrintCompilation来看:
java -server -Xcomp -XX:+PrintCompilation ClasspathTest
... 567 270 b java.lang.reflect.Method::getModifiers (5 bytes) 567 271 b ClasspathTest::main (24 bytes) 567 271 made not entrant ClasspathTest::main (24 bytes) 567 272 b java.io.File::toURL (23 bytes) 567 272 made not entrant java.io.File::toURL (23 bytes) 568 273 b java.io.File::getAbsolutePath (8 bytes) ...
有的,这个main()方法编译了。
但是,HotSpot的server编译器到底给main()方法生成了怎样的代码呢?用-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly来看:(用法参考以前一帖)
java -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly ClasspathTest
# {method} 'main' '([Ljava/lang/String;)V' in 'ClasspathTest' # parm0: ecx = '[Ljava/lang/String;' # [sp+0x10] (sp of caller) 0x00a33b00: mov %eax,-0x3000(%esp) 0x00a33b07: push %ebp 0x00a33b08: sub $0x8,%esp ;*synchronization entry ; - ClasspathTest::main@-1 (line 19) 0x00a33b0e: mov $0xa,%ecx 0x00a33b13: call 0x0099c700 ; OopMap{off=24} ;*new ; - ClasspathTest::main@0 (line 19) ; {runtime_call} 0x00a33b18: int3 ;*new ; - ClasspathTest::main@0 (line 19)
可以看到,生成的代码只做了这么几件事情:
1、检查调用栈是否要溢出了(0x00a33b00)
2、保存老栈帧信息,建立新栈帧(0x00a33b07-0x00a33b08)
3、?(0x00a33b0e)
4、不应该跑到这里来,否则中断(0x00a33b18)
这问号就是有趣的地方了。如果这个问号表示的代码不足以执行main()的内容的话,那main()到底是如何被执行的呢?
我们可以用另一组参数来了解这神秘的“0x0099c700”地址到底是什么东西,-XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode
java -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintStubCode ClasspathTest
Decoding UncommonTrapBlob@0x0099c700 0x0099c6c8 [Disassembling for mach='i386'] 0x0099c700: sub $0xc,%esp 0x0099c703: mov %ebp,0x8(%esp) 0x0099c707: emms 0x0099c709: mov %fs:0x0(,%eiz,1),%edx 0x0099c711: mov -0xc(%edx),%edx 0x0099c714: mov %esp,0x118(%edx) 0x0099c71a: mov %edx,(%esp) 0x0099c71d: mov %ecx,0x4(%esp) 0x0099c721: call 0x6dc77300 0x0099c726: mov %fs:0x0(,%eiz,1),%ecx 0x0099c72e: mov -0xc(%ecx),%ecx 0x0099c731: movl $0x0,0x118(%ecx) 0x0099c73b: mov %eax,%edi 0x0099c73d: add $0xc,%esp 0x0099c740: mov (%edi),%ecx 0x0099c742: add %ecx,%esp 0x0099c744: mov 0xc(%edi),%ebx 0x0099c747: mov %esp,%ecx 0x0099c749: mov %ebx,-0x1000(%ecx) 0x0099c74f: sub $0x1000,%ecx 0x0099c755: sub $0x1000,%ebx 0x0099c75b: jg 0x0099c749 0x0099c75d: mov %ebx,(%ecx) 0x0099c75f: mov %ebx,-0x1000(%ecx) 0x0099c765: mov 0x14(%edi),%ecx 0x0099c768: pop %esi 0x0099c769: mov 0x10(%edi),%esi 0x0099c76c: mov 0x8(%edi),%ebx 0x0099c76f: mov %ebx,0x20(%edi) 0x0099c772: mov 0x24(%edi),%ebp 0x0099c775: mov %esp,0x2c(%edi) 0x0099c778: mov 0x4(%edi),%ebx 0x0099c77b: sub %ebx,%esp 0x0099c77d: mov (%esi),%ebx 0x0099c77f: sub $0x8,%ebx 0x0099c782: pushl (%ecx) 0x0099c784: push %ebp 0x0099c785: mov %esp,%ebp 0x0099c787: sub %ebx,%esp 0x0099c789: mov 0x2c(%edi),%ebx 0x0099c78c: movl $0x0,-0x8(%ebp) 0x0099c793: mov %ebx,-0x4(%ebp) 0x0099c796: mov %esp,0x2c(%edi) 0x0099c799: add $0x4,%esi 0x0099c79c: add $0x4,%ecx 0x0099c79f: decl 0x20(%edi) 0x0099c7a2: jne 0x0099c77d 0x0099c7a4: pushl (%ecx) 0x0099c7a6: push %ebp 0x0099c7a7: mov %esp,%ebp 0x0099c7a9: sub $0x8,%esp 0x0099c7ac: mov %fs:0x0(,%eiz,1),%edi 0x0099c7b4: mov -0xc(%edi),%edi 0x0099c7b7: mov %ebp,0x120(%edi) 0x0099c7bd: mov %esp,0x118(%edi) 0x0099c7c3: mov %edi,(%esp) 0x0099c7c6: movl $0x2,0x4(%esp) 0x0099c7ce: call 0x6dc75d40 0x0099c7d3: mov %fs:0x0(,%eiz,1),%edi 0x0099c7db: mov -0xc(%edi),%edi 0x0099c7de: movl $0x0,0x118(%edi) 0x0099c7e8: movl $0x0,0x120(%edi) 0x0099c7f2: mov %ebp,%esp 0x0099c7f4: pop %ebp 0x0099c7f5: ret 0x0099c7f6: .byte 0xc1 0x0099c7f7: .byte 0x4
嗯,很长很诡异的代码对吧?实际上这块代码是一个“uncommon trap”,也就是当HotSpot的server编译器遇到它觉得不会发生的、或不方便处理的部分的时候会用到的一块代码。
前面提到的“问号”的代码,就是用于跳进该“uncommon trap”的。
但main()方法为啥刚一进去就要无条件跳进一个uncommon trap呢?这次我们换用一个fastdebug版的JDK 6 update 25,然后用-XX:+PrintOptoAssembly来看看:
java -server -Xcomp -XX:+PrintOptoAssembly ClasspathTest
000 B1: # N1 <- BLOCK HEAD IS JUNK Freq: 1 000 # stack bang PUSHL EBP SUB ESP,8 # Create frame 00e MOV ECX,#10 013 CALL,static wrapper for: uncommon_trap(reason='unloaded' action='reinterpret' index='10') # ClasspathTest::main @ bci:0 L[0]=_ L[1]=_ # OopMap{off=24} 018 INT3 ; ShouldNotReachHere 018
代码里嵌着的注释说得很明白了,跳进uncommon trap的原因是“unloaded”,也就是该方法需要用的类要么尚未加载,要么虽然加载过但已经卸载掉了。相应采取的措施就是“reinterpret”,也就是退回到解释器去执行。
具体做检查的代码在这里:
void ciTypeFlow::StateVector::do_new(ciBytecodeStream* str) { bool will_link; ciKlass* klass = str->get_klass(will_link); if (!will_link || str->is_unresolved_klass()) { trap(str, klass, str->get_klass_index()); } else { push_object(klass); } }
也就是HotSpot的JIT编译器做初步类型分析的时候就已经发现有问题了。
看到了么?HotSpot的server编译器只是等同于给例子里的main()生成了个解释器入口,让它跳进去而已,并没有真的把main()方法编译出来。
所以说HotSpot的server编译器其实跟JRockit的JIT编译器在这点上都偷懒了…
只不过HotSpot能退回到解释器里,所以编译器偷懒了没关系,程序还能跑,就是慢一些;JRockit的编译器偷懒了,Java程序搞不好就得撞墙了
HotSpot的client编译器在遇到编译时仍未resolve的符号的话,会在使用这些符号的位置生成一个call thunk,调用一个用于符号解析的thunk,解析好之后把直接引用patch回到原本的call thunk上。这样不用只为解决符号引用的resolution就掉回到解释器里,但生成的代码质量也会稍微差一些。
P.S. 顺带一提:HotSpot的server编译器并不会在接受某个方法的编译请求时强制要求里面涉及的所有类型已经被加载,只要求在方法签名里出现的类型在编译前已经被加载,并要求在编译前该方法里涉及的所有的字符串常量已经resolve完(具体执行这些约束的时负责分派编译请求的CompilerBroker而不是server编译器自身,见回复里的讨论)。
所以这个例子就算给了-classpath ".;foo"也会得到一样的、只含一个uncommon trap的main()方法。
P.P.S. 顺带找个地方记下ciTypeFlow的作用:
http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2008-May.txt
引用
From John.Rose at Sun.COM Fri May 16 11:23:22 2008
From: John.Rose at Sun.COM (John Rose)
Date: Fri, 16 May 2008 11:23:22 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080516084237.GA3704@redhat.com>
References: <20080516084237.GA3704@redhat.com>
Message-ID: <200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
On May 16, 2008, at 1:42 AM, Gary Benson wrote:
> Do I have to do something to tell the CompileBroker not
> to feed me methods full of unloaded stuff? Oh, and I'm using -Xmixed.
The typeflow pass builds the basic block model and typestates
consumed by the parser. You can't build phis correctly without that
stuff.
(An earlier version tried to parse, find blocks, and compute phi
types all on the fly, but it didn't work out, so ciTypeFlow was added
as a first pass.)
(The new typestate maps might change this a little, but we have to
compile w/o the maps anyway.)
The basic block model is pruned at unreached bytecodes which would
provoke class loading.
As a result, the parser can (mostly) ignore unloaded classes, which
removes lots of buggy edge cases.
Do you use ciTypeFlow in your JIT?
-- John
From John.Rose at Sun.COM Tue May 20 10:59:04 2008
From: John.Rose at Sun.COM (John Rose)
Date: Tue, 20 May 2008 10:59:04 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080520074445.GA3861@redhat.com>
References: <20080516084237.GA3704@redhat.com>
<200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
<20080520074445.GA3861@redhat.com>
Message-ID: <E0C35D5A-DA47-48AD-BA2D-EFC6F6F4A720@sun.com>
On May 20, 2008, at 12:44 AM, Gary Benson wrote:
> That's awesome! I wasn't using it until yesterday but I am now
I'm glad it's helpful!
> So does the ciTypeFlow pass actually load the unloaded classes for
> you?
No, the JIT tries pretty hard not to load classes. IIRC, the only
exception to this rule is the call to load_signature_classes in
compileBroker.cpp.
JIT compilation should be transparent to Java execution, but loading
classes causes class loader code to execute. If the JIT causes
bytecode execution, then the JIT can cause application state changes,
which explores new application states unnecessarily. This can expose
JIT-entangled bugs in the application. You want this in stress
testing, but not in the field.
The JVM spec. allows class loading--not initialization--for any
reason, but it's better (for system reproducibility) if the JIT has
no detectable effect on app. state except speedups.
-- John
From: John.Rose at Sun.COM (John Rose)
Date: Fri, 16 May 2008 11:23:22 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080516084237.GA3704@redhat.com>
References: <20080516084237.GA3704@redhat.com>
Message-ID: <200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
On May 16, 2008, at 1:42 AM, Gary Benson wrote:
> Do I have to do something to tell the CompileBroker not
> to feed me methods full of unloaded stuff? Oh, and I'm using -Xmixed.
The typeflow pass builds the basic block model and typestates
consumed by the parser. You can't build phis correctly without that
stuff.
(An earlier version tried to parse, find blocks, and compute phi
types all on the fly, but it didn't work out, so ciTypeFlow was added
as a first pass.)
(The new typestate maps might change this a little, but we have to
compile w/o the maps anyway.)
The basic block model is pruned at unreached bytecodes which would
provoke class loading.
As a result, the parser can (mostly) ignore unloaded classes, which
removes lots of buggy edge cases.
Do you use ciTypeFlow in your JIT?
-- John
From John.Rose at Sun.COM Tue May 20 10:59:04 2008
From: John.Rose at Sun.COM (John Rose)
Date: Tue, 20 May 2008 10:59:04 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080520074445.GA3861@redhat.com>
References: <20080516084237.GA3704@redhat.com>
<200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
<20080520074445.GA3861@redhat.com>
Message-ID: <E0C35D5A-DA47-48AD-BA2D-EFC6F6F4A720@sun.com>
On May 20, 2008, at 12:44 AM, Gary Benson wrote:
> That's awesome! I wasn't using it until yesterday but I am now
I'm glad it's helpful!
> So does the ciTypeFlow pass actually load the unloaded classes for
> you?
No, the JIT tries pretty hard not to load classes. IIRC, the only
exception to this rule is the call to load_signature_classes in
compileBroker.cpp.
JIT compilation should be transparent to Java execution, but loading
classes causes class loader code to execute. If the JIT causes
bytecode execution, then the JIT can cause application state changes,
which explores new application states unnecessarily. This can expose
JIT-entangled bugs in the application. You want this in stress
testing, but not in the field.
The JVM spec. allows class loading--not initialization--for any
reason, but it's better (for system reproducibility) if the JIT has
no detectable effect on app. state except speedups.
-- John
引用
From John.Rose at Sun.COM Thu May 22 11:02:35 2008
From: John.Rose at Sun.COM (John Rose)
Date: Thu, 22 May 2008 11:02:35 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080522091725.GB3794@redhat.com>
References: <20080516084237.GA3704@redhat.com>
<200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
<20080520074445.GA3861@redhat.com>
<E0C35D5A-DA47-48AD-BA2D-EFC6F6F4A720@sun.com>
<20080522091725.GB3794@redhat.com>
Message-ID: <3950F6EA-B65B-485F-B336-D64F048B681E@sun.com>
On May 22, 2008, at 2:17 AM, Gary Benson wrote:
> So the 'assert(will_link, "typeflow responsibility")' bits aren't
> being hit because the typeflow pass bails out? (ie env()->failing()
> returns true?) Will the compile broker retry the compilation later?
No, typeflow ends such a block with a "trap". (If we bailed out on
every unloaded class, we'd almost never compile anything.) A trap is
like a branch to the interpreter (deopt). The parser is responsible
for respecting those trap markings. A basic block that ends in a
trap never gets (in compiled code) to the branch or return that ends
the basic block in the bytecodes.
-- John
From: John.Rose at Sun.COM (John Rose)
Date: Thu, 22 May 2008 11:02:35 -0700
Subject: Failing typeflow responsibility assertions
In-Reply-To: <20080522091725.GB3794@redhat.com>
References: <20080516084237.GA3704@redhat.com>
<200E1632-3850-445C-B32E-7A0F6A497BAC@sun.com>
<20080520074445.GA3861@redhat.com>
<E0C35D5A-DA47-48AD-BA2D-EFC6F6F4A720@sun.com>
<20080522091725.GB3794@redhat.com>
Message-ID: <3950F6EA-B65B-485F-B336-D64F048B681E@sun.com>
On May 22, 2008, at 2:17 AM, Gary Benson wrote:
> So the 'assert(will_link, "typeflow responsibility")' bits aren't
> being hit because the typeflow pass bails out? (ie env()->failing()
> returns true?) Will the compile broker retry the compilation later?
No, typeflow ends such a block with a "trap". (If we bailed out on
every unloaded class, we'd almost never compile anything.) A trap is
like a branch to the interpreter (deopt). The parser is responsible
for respecting those trap markings. A basic block that ends in a
trap never gets (in compiled code) to the branch or return that ends
the basic block in the bytecodes.
-- John
评论
11 楼
RednaxelaFX
2011-05-13
wkoffee 写道
引用
wkoffee 写道
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
在jvm spec 2.17.2 中
"The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError will be thrown at any point in the program that (directly or indirectly) uses the type:"
而且下面列出NoClassDefFoundError是loading的error,那它应该在用到该类型的时候抛出。在这个例子中,main方法执行的入口时候并没有用到Foo,只有在new Foo的时候用到,jrockit的做法相当于prefetch或者group loading,但jvm有责任确保不应该因为这个引起额外的异常,(这里有点绕,我理解是如果有异常,那不使用prefetch or group loading的classloader也会报错)
这个例子里使用反射不知道是不是很重要,URLClassLoader的addUrl方法是protected的,自定义classloader就可以绕过它。但不知道是不是因为用了反射才会出现这个结果。
前面的解释都说得通。但我觉得问题点在于system class loader到底是个什么类型的对象,在JVM规范里没定义,所以本来Java应用不应该能够假定它会是URLClassLoader的子类的实例。这样的话,依赖该class loader有addURL方法、并且通过它修改class path的做法的结果会怎样本来就应该也是未定义的吧。
刚试着搜了一下,在JVM规范里没找到"system class loader"的定义。这玩儿是在哪里定义的呢?
10 楼
wkoffee
2011-05-12
引用
但CompilerBroker在tiered compilation里多数时候都在跟compiled code打交道,从compiled code里跟compiler打交道算不算是整个compilation system的一部分就模糊了。
能详细说说这一点吗,我印象中CompilerBroker只是发起请求,tiered compilation时为什么compiled code要和它打交道。
9 楼
wkoffee
2011-05-12
引用
wkoffee 写道
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
在jvm spec 2.17.2 中
"The loading process is implemented by the class ClassLoader and its subclasses. Different subclasses of ClassLoader may implement different loading policies. In particular, a class loader may cache binary representations of classes and interfaces, prefetch them based on expected usage, or load a group of related classes together. These activities may not be completely transparent to a running application if, for example, a newly compiled version of a class is not found because an older version is cached by a class loader. It is the responsibility of a class loader, however, to reflect loading errors only at points in the program where they could have arisen without prefetching or group loading.
If an error occurs during class loading, then an instance of one of the following subclasses of class LinkageError will be thrown at any point in the program that (directly or indirectly) uses the type:"
而且下面列出NoClassDefFoundError是loading的error,那它应该在用到该类型的时候抛出。在这个例子中,main方法执行的入口时候并没有用到Foo,只有在new Foo的时候用到,jrockit的做法相当于prefetch或者group loading,但jvm有责任确保不应该因为这个引起额外的异常,(这里有点绕,我理解是如果有异常,那不使用prefetch or group loading的classloader也会报错)
这个例子里使用反射不知道是不是很重要,URLClassLoader的addUrl方法是protected的,自定义classloader就可以绕过它。但不知道是不是因为用了反射才会出现这个结果。
8 楼
RednaxelaFX
2011-05-12
wkoffee 写道
发起compiler请求到底算不算compiler的职责,每个人可以自己理解,我个人认为不算。
嗯,CompilerBroker名字都已经这么叫了,也就是个转发者的角色。如果说它是解释器与JIT编译器之间的接口上的东西也对,那么两边都算不上。但CompilerBroker在tiered compilation里多数时候都在跟compiled code打交道,从compiled code里跟compiler打交道算不算是整个compilation system的一部分就模糊了。
不过你说得对,我应该把正文的最后那段改改,强调只是个约束而不是opto主动发起的动作。
wkoffee 写道
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
先前没仔细看这条回复,请问严格来说JRockit的这个做法是违反了第几版JVM规范的哪部分?给我的感觉是一个只能通过强行调用non-public方法做到的事情不会是规范里会写到的。
7 楼
RednaxelaFX
2011-05-11
wkoffee 写道
这个要求究竟有多大实际意义也很可疑,正常的java程序在发起请求的时候这些类应该都已加载过,即使有个别极端情况没有加载,compiler简单的bailout就可以,所以我觉得这个看上去更像是为了做测试所加的内容。
如果不是-Xcomp的话,以默认的mixed mode是不应该遇到方法签名上有未加载的类型的。就这点而言在HotSpot上跑的一般Java程序是不会遇到帖子里说的问题的。
话说回来,原本为啥会弄CTW模式来测试HotSpot的编译器的…CTW也确实就是只“为了做测试”而存在的模式,而那个模式下会出现很多奇怪的情况,跟-Xcomp有相似之处
6 楼
wkoffee
2011-05-11
发起compiler请求到底算不算compiler的职责,每个人可以自己理解,我个人认为不算。
这个要求究竟有多大实际意义也很可疑,正常的java程序在发起请求的时候这些类应该都已加载过,即使有个别极端情况没有加载,compiler简单的bailout就可以,所以我觉得这个看上去更像是为了做测试所加的内容。
这个要求究竟有多大实际意义也很可疑,正常的java程序在发起请求的时候这些类应该都已加载过,即使有个别极端情况没有加载,compiler简单的bailout就可以,所以我觉得这个看上去更像是为了做测试所加的内容。
5 楼
RednaxelaFX
2011-05-11
wkoffee 写道
这段代码是生成编译请求的工作,其实还是java thread在执行,compiler thread不会执行的。从注释看是c2的prerequesites,只是一些细节的东西,并不值得深入。
嗯,compiler thread是不会调用Java-level方法的。不过前面也一直没说过那些加载动作是在compiler thread上做的吧…是怎么掉进这段对话的orz
值不值得深入要看目的了。如果关注opto里的很多奇怪的约束,免得改代码的时候不小心弄坏的话,那各种细节都不得不留意。除此之外的话…
4 楼
wkoffee
2011-05-11
这段代码是生成编译请求的工作,其实还是java thread在执行,compiler thread不会执行的。从注释看是c2的prerequesites,只是一些细节的东西,并不值得深入。
3 楼
RednaxelaFX
2011-05-10
wkoffee 写道
引用
P.S. 顺带一提:HotSpot的server编译器并不会在编译某个方法前强制加载里面涉及的所有类型,只会强制加载在方法签名里出现的类型,并强制resolve掉所有的字符串常量。所以这个例子就算给了-classpath ".;foo"也会得到一样的、只含一个uncommon trap的main()方法。
印象中hotspot的compiler不负责加载任何java类,加载类需要执行类的<clinit>方法,compiler thread是不会执行任何java方法的,所以应该还是java thread来加载类。
可以看看CompilerBroker的实现。脏活累活opto都交给别人干了 XD
hotspot/src/share/vm/compiler/compileBroker.cpp
1031 // some prerequisites that are compiler specific 1032 if (compiler(comp_level)->is_c2()) { 1033 method->constants()->resolve_string_constants(CHECK_0); 1034 // Resolve all classes seen in the signature of the method 1035 // we are compiling. 1036 methodOopDesc::load_signature_classes(method, CHECK_0); 1037 }
2 楼
wkoffee
2011-05-10
引用
P.S. 顺带一提:HotSpot的server编译器并不会在编译某个方法前强制加载里面涉及的所有类型,只会强制加载在方法签名里出现的类型,并强制resolve掉所有的字符串常量。所以这个例子就算给了-classpath ".;foo"也会得到一样的、只含一个uncommon trap的main()方法。
印象中hotspot的compiler不负责加载任何java类,加载类需要执行类的<clinit>方法,compiler thread是不会执行任何java方法的,所以应该还是java thread来加载类。
1 楼
wkoffee
2011-05-10
严格的说jrockit的做法是不符合java规范的,jvm的规范要求在第一次访问类的时候加载,这个程序在执行new Foo的时候classpath已经设好了,classloader应该可以加载类,所以这是个合法的程序。jrockit简单的退出是有问题的。
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
Java 8与静态工具类
2014-03-19 08:43 16280以前要在Java里实现所谓“静态工具类”(static uti ... -
Java 8的default method与method resolution
2014-03-19 02:23 10454先看看下面这个代码例子, interface IFoo { ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
基于LLVM实现VM的JIT的一些痛点
2014-01-07 17:25 0同事Philip Reames Sanjoy Das http ... -
tailcall notes
2013-12-27 07:42 0http://blogs.msdn.com/b/clrcode ... -
《自制编程语言》的一些笔记
2013-11-24 00:20 0http://kmaebashi.com/programmer ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22397(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局 (0): 拿在手上的是什么
2013-11-04 18:22 21496(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对C语义的for循环的基本代码生成模式
2013-10-19 23:12 21875之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ...
相关推荐
"深入JVM系列-JIT编译详解1" 在这篇文章中,我们将深入探讨JVM中的JIT编译技术。JIT(Just In Time)编译器是一种即时编译技术,它可以加速Java程序的执行速度。 JIT编译过程 -------- 在执行Java程序时,JVM会将...
Jarscan能够静态分析JAR文件,找出可能无法被JIT编译的方法。此外,启用JVM的`-XX:+PrintCompilation`选项可以在运行时记录编译信息,帮助开发者理解哪些方法正在被JIT编译。 结合Jarscan和`PrintCompilation`的...
3. **Trace编译**:将提取到的热点路径编译成本地机器码。 4. **Trace合并**:将编译后的Trace重新组合成可执行的代码序列。 5. **动态更新**:根据程序执行情况的变化动态调整已编译的Trace。 #### 性能评估 为了...
JIT编译有两个主要类型:客户端编译器(Client Compiler),适用于快速启动但对性能要求不高的场景;服务器编译器(Server Compiler),延迟启动,优化程度更高,适合长时间运行的应用。 3. **热点代码识别**: ...
1. **JIT编译过程**:在Android中,Dalvik虚拟机(或者后来的ART,Android RunTime)使用了JIT技术。当应用程序首次运行时,字节码被解释执行,但随着运行,JIT会收集执行信息,对热点代码进行编译,以提高后续执行...
在IT行业中,"JIT实现拓扑展现"这个主题涉及到的是动态编译技术和网络拓扑图的可视化。这里,我们主要探讨JIT(Just-In-Time)编译器以及如何利用它来优化程序性能,同时也会关注如何通过编程手段将网络拓扑结构以...
攻击者可以利用这一点,在JIT编译过程中注入恶意代码,从而绕过DEP和ASLR,实现对目标系统的控制。 ### IE8的保护机制 Internet Explorer 8引入了永久性的DEP保护,这使得传统的Heap Spray攻击方法失效。IE8通过...
本文档探讨了两种新型技术来绕过这些缓解措施:指针推断(Pointer Inference)和即时编译喷射(JIT Spraying)。这两种技术充分利用了浏览器内广泛使用的高级脚本解释器或虚拟机的攻击面。 #### 关键技术介绍 ####...
- **编译时机**:JIT编译器并不是一开始就将所有代码编译成机器码,而是根据代码的热冷程度来决定何时进行编译。这样可以避免不必要的编译开销。 - **编译策略**:通常,JIT编译器会监控代码执行频率,并将最频繁...
在riscv-jit-emulator中,JIT编译被用来动态转换RISC-V指令,以便在模拟器内部更快速地执行。 沙箱环境是运行代码的一种安全机制,它可以限制程序的访问权限,防止它们对系统造成破坏或溢出。在这个模拟器中,...
对于未预编译的ASP.NET应用,当用户首次访问一个页面时,该页面及其依赖项会被JIT编译。JIT编译器会将IL代码转换为特定平台的机器码,确保代码运行效率。 3. **ASP.NET的编译过程**: - **标记编译(Markup ...
《编译系统透视:图解编译原理》是深入理解计算机科学中不可或缺的一环,它为我们揭示了程序语言从源代码到机器可执行代码的转化过程。编译器是这个转化过程的核心,它将高级语言翻译成计算机可以直接执行的低级语言...
5. JIT编译:运行时,Just-In-Time编译器将IL代码编译成针对特定平台的机器码。 反编译VB程序主要涉及以下几个方面: 1. 使用反编译工具:市面上有一些专门用于反编译.NET程序的工具,如Reflector、ILSpy、dotPeek...
3. **JIT编译**:接下来,LLVM的JIT编译器将IR编译成特定平台的机器码,这个过程几乎是即时完成的。 4. **数值计算**:最后,生成的机器码可以直接执行,对给定的数值进行快速计算。 使用sympy-llvm的优势在于,它...
Java动态编译是一种在程序运行时将源代码转换为字节码的技术,它使得程序...无论是JVM内置的JIT编译机制,还是第三方库提供的动态代码生成工具,都是Java生态系统中不可或缺的一部分,它们共同推动了Java技术的发展。
与传统的解释执行不同,JIT编译会将编译后的代码缓存起来,以便再次使用时无需重新编译,从而提高效率。JIT编译技术使得动态更新代码成为可能,尤其是在Android平台上。 ### Unity不同设置对应的Mono源码选择和编译...
JIT编译是BPF的一个重要特性,它将BPF字节码转换为机器码,以提高执行效率。BPF JIT编译器将BPF程序转换为特定架构的本地代码,从而在内核中运行时无需解释执行,提高了性能。 在`board-generic.c`文件中,我们可能...
由于反编译可能会侵犯到原软件的版权,因此在没有得到授权的情况下,商业用途的反编译行为可能涉及到法律风险。在进行此类操作时,确保遵循合法和道德的规范,尊重他人的知识产权。 总的来说,反编译工具为开发者...
"反编译软件能反编译.NET代码"这一主题涉及到的主要知识点包括反编译原理、.NET代码的可逆工程以及相关的反编译工具。 首先,我们需要理解什么是反编译。反编译是将已编译的机器语言代码转换回高级语言的过程,其...
对于Java开发者而言,这意味着简单的微基准测试可能无法准确反映实际性能,因为它们可能未考虑到JIT编译的影响。因此,设计全面的性能测试需要考虑代码执行的热身阶段、JIT编译的触发条件以及各种优化技术的作用。 ...