Tag: 编译器优化

这个Java代码如何加速?

我正在尝试对Java执行简单任务的速度进行基准测试:将大文件读入内存,然后对数据执行一些无意义的计算。 所有类型的优化都很重要。 无论是以不同方式重写代码还是使用不同的JVM,都会欺骗JIT。 输入文件是由逗号分隔的5亿个32位整数对列表。 喜欢这个: 44439,5023 33140,22257 … 这个文件在我的机器上需要5.5GB 。 该程序不能使用超过8GB的RAM,只能使用一个线程 。 package speedracer; import java.io.FileInputStream; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class Main { public static void main(String[] args) { int[] list = new int[1000000000]; long start1 = System.nanoTime(); parse(list); long end1 = System.nanoTime(); System.out.println(“Parsing took: ” + (end1 – start1) / 1000000000.0); int rs […]

Java优化器和冗余arrays评估

这是关于Java优化的一个非常基本的问题。 如果你有一个简单的for循环迭代数组并在循环的头部使用array.length而不是之前评估它,那么你只做一次(这是我几乎总是这样做): for(int i=0; i<array.length;i++) { … } 可以对语句进行优化,以便JVM知道数组是否在循环的持续时间内发生变化,这样它每次都不会重新评估array.length吗?

用于重复方法调用的Java编译器优化?

java编译器(JDK1.6.0_21中的默认javac)是否会优化代码以防止使用相同的参数一遍又一遍地调用相同的方法? 如果我写了这段代码: public class FooBar { public static void main(String[] args) { foo(bar); foo(bar); foo(bar); } } 方法foo(bar)只会运行一次吗? 如果是这样,有没有办法阻止这种优化? (我试图比较运行时的两个算法,一个迭代和一个比较,我想多次调用它们来获得一个代表性的样本) 任何见解都会非常感激; 我把这个问题带到了疯狂的地步(虽然我的计算机很快就疯了,所以我继续添加方法调用,直到我在43671行得到code too large错误)。

慢JDK8编译

尝试在一个大项目上升级到JDK8,与JDK7相比,JDK8上的编译速度非常慢。 以详细模式运行编译器,JDK8编译器停止在从服务器到客户端的实体的大生成转换器类(映射)。 在几种情况下,转换器方法从同一Mapping类调用其他转换器方法。 作为一种解决方法,尝试将Mapping文件拆分为多个文件。 仅在编译Mapping类或包含项目(projectA)时,这显着提高了性能。 但是对于从projectA调用转换器方法的其他项目,编译时间非常慢。 另一个解决方法是使所有转换方法返回null,而不是调用任何其他方法。 同样,性能对projectA有利,但不适用于依赖项目。 ProjectA使用generics,但由于它与JDK6兼容,后者没有引入广义类型推断,可能是另一个导致这种减速的JDK8错误。 因此可能脱离上下文但是对于通用类型推断,下面的一些线程建议升级到JDK9。 但由于它尚未发布,因此升级并不是一个可行的选择。 如果修复程序的后端移植到JDK8,那将是理想的选择。 这是在以下StackOverflow线程中请求的,但尚未得到Oracle团队的回复。 使用jOOQ 3.6 +,纯SQL和javac编译器进行慢速编译 我附上了两个关于堆在JDK7和JDK8中的外观截图。 这可能是导致JDK8放缓的原因吗? 谢谢! 更新20160314 Mapping类的转换器方法如下所示: public static ResponseItemVO convert (ResponseItem pArg0){ if(pArg0==null){ return null; } ResponseItemVO ret = new ResponseItemVO(); ret.setErrorDetails(pArg0.getErrorDetails()); ret.setResult(Mapping.convert(pArg0.getResult())); ret.setIdentifier(Mapping.convert(pArg0.getIdentifier())); return ret; } VO看起来像: public class ResponseItemVO extends ResultVO { public ResponseItemVO() {} } JDK7堆: JDK8堆:

用Java编写的编译器:Peephole优化器实现

我正在为Pascal的子集编写一个编译器。 编译器为制造的机器生成机器指令。 我想为这种机器语言编写一个窥视孔优化器,但是我在替换一些更复杂的模式时遇到了麻烦。 窥孔优化器规范 我研究了几种不同的编写窥视孔优化器的方法,并且我已经确定了一种后端方法: 每次生成机器指令时,Encoder都会调用emit()函数。 emit(Instruction currentInstr)检查窥视孔优化表: 如果当前指令与模式的尾部匹配: 检查先前发出的匹配说明 如果所有指令都与模式匹配,则应用优化,修改代码存储的尾端 如果未找到优化,则照常发出指令 目前的设计方法 这个方法很简单,这是我遇到麻烦的实现。 在我的编译器中,机器指令存储在Instruction类中。 我写了一个InstructionMatch类,它存储了用于匹配机器指令的每个组件的正则表达式。 如果模式匹配某些机器指令instr则其equals(Instruction instr)方法返回true 。 但是,我无法完全应用我的规则。 首先,我觉得根据我目前的做法,我最终会得到一堆不必要的物品。 鉴于窥视孔优化数字的完整列表可以编号大约400个模式,这将失控。 此外,我实际上无法使用这种方法进行更难的替换(参见“我的问题”)。 替代方法 我读过的一篇论文将先前的指令折叠成一个长字符串,使用正则表达式匹配和替换,并将字符串转换回机器指令。 这对我来说似乎是一个糟糕的方法,如果我错了,请纠正我。 示例模式,模式语法 x: JUMP x+1; x+1: JUMP y –> x: JUMP y LOADL x; LOADL y; add –> LOADL x+y LOADA d[r]; STOREI (n) –> STORE (n) d[r] 请注意,这些示例模式中的每一个都只是以下机器指令模板的人类可读表示: op_code […]

拥有许多小方法是否有助于JIT编译器进行优化?

在最近关于如何优化某些代码的讨论中,我被告知将代码分解为许多小方法可以显着提高性能,因为JIT编译器不喜欢优化大型方法。 我不确定这一点,因为看起来JIT编译器本身应该能够识别自包含的代码段,而不管它们是否在自己的方法中。 任何人都可以确认或反驳这种说法吗?

是否可以阻止JIT优化远离方法调用?

我们正在构建一个用于Java Byte Code程序的平均案例运行时分析的工具。 其中一部分是测量实际运行时间。 因此,我们将采用任意的,用户提供的方法,可能有也可能没有结果,可能有也可能没有副作用(例子包括Quicksort,factorial,dummy嵌套循环……)并执行它(使用reflection),测量经过的时间。 (无论我们是否正确地进行基准测试,除了这里的要点之外。) 在基准测试代码中,我们显然不对结果做任何事情(有些方法甚至没有结果)。 因此,没有人知道JIT可能会做什么,事实上我们已经观察到它似乎有时会优化整个基准测试方法。 由于基准测试方法实际上并未单独使用,因此基准测试无用。 我们怎样才能阻止JIT这样做呢? 我们不想完全关闭它,因为基准测试需要很长时间,而且我们想要对“真实”运行时进行基准测试(因此我们希望JIT在方法内部处于活动状态)。 我知道这个问题但是给定的场景太窄了; 我们不知道结果类型(如果有的话),因此不能以某种方式使用结果,JIT认为没有用处。

是否由Java编译器优化了空的同步块?

假设在我的代码中某处我写了一个空的synchronized块: synchronized(obj){ //No code here } 因为同步块不包含任何代码,JIT编译器是否会通过不锁定obj来优化它,因为它没有用? Java编译器做类似的技巧,如Lock粗化,但这个同步块也会被优化掉吗? 编辑: 根据assylias的观点, synchronized(new Object()){ //empty block } JIT编译器现在能够优化它,因为我使用的是一个不会逃避我的方法的Object吗?

查找方法的字节码大小

我试图找出一个方法的字节码大小,因为我想确保它足够小,可以通过编译器优化来内联。 我看到内联方法的默认最大大小是35,所以如果方法大于那个,我将修改代码或将其分解为多个方法。 我有一个方法生成下面的字节码(通过IntelliJ IDEA的ASM字节码大纲插件反汇编)。 如何判断该方法的字节码大小? LINENUMBER似乎引用了原始源代码的行号。 TIA public static mergeNativeArrays([Ljava/lang/Object;[Ljava/lang/Object;IZ)[Ljava/lang/Object; L0 LINENUMBER 865 L0 ALOAD 0 ASTORE 4 L1 LINENUMBER 867 L1 ILOAD 2 IFGE L2 L3 LINENUMBER 868 L3 ALOAD 0 ARRAYLENGTH ISTORE 2 L2 LINENUMBER 870 L2 FRAME APPEND [[Ljava/lang/Object;] ILOAD 2 ALOAD 1 ARRAYLENGTH IADD ISTORE 5 L4 LINENUMBER 872 L4 ALOAD […]

(如何)Java JIT编译器优化我的代码?

我正在编写相当低级别的代码,必须针对速度进行高度优化。 每个CPU周期都很重要。 由于代码是用Java编写的,所以我不能像C中那样写低级别,但是我希望能够从VM中获取所有内容。 我正在处理一个字节数组。 我的代码有两个部分,我现在主要感兴趣。 第一个是: int key = (data[i] & 0xff) | ((data[i + 1] & 0xff) << 8) | ((data[i + 2] & 0xff) << 16) | ((data[i + 3] & 0xff) << 24); 第二个是: key = (key <>> 17); 从性能来看,我猜这些陈述没有按照我的预期进行优化。 第二个陈述基本上是ROTL 15, key 。 第一个语句将4个字节加载到int中。 如果访问的字节恰好为负,则0xff掩码仅用于补偿由隐式转换为int导致的添加符号位。 这应该很容易转换为高效的机器代码,但令我惊讶的是,如果我删除掩码,性能会上升。 (这当然会破坏我的代码,但我很想知道会发生什么。) 这里发生了什么? 最常见的Java VM是否会在JIT期间以期望优秀的C ++编译器优化等效C […]