2013-12-19 33 views
2

我正在编写代码,我正在对数组值进行一些计算并将结果存储回数组。演示代码如下 -将值分配给数组索引并将值分配给变量在java中的性能差异

public class Test { 
    private int[] x = new int[100000000]; 
    /** 
    * @param args 
    * @throws Exception 
    */ 
    public static void main(String[] args) throws Exception { 
     Test t = new Test(); 
     long start = System.nanoTime(); 
     for(int i=0;i<100000000;i++) { 
      t.testing(i); 
     } 
     System.out.println("time = " + (System.nanoTime() - start)/1000); 
    } 

    public void testing(int a) throws Exception { 
     int b=1,c=0; 
     if(b<c || b < 1) { 
      throw new Exception("Invalid inputs"); 
     } 
     int d= a>>b; 
     int e = a & 0x0f; 
     int f = x[d]; 
     int g = x[e]; 
     x[d] = f | g; 
    } 
} 

程序的主要逻辑在于

int d= a>>b; 
int e = a & 0x0f; 
x[d] = f | g; 

当我测试此代码,花了110毫秒。 但不是assiging结果反馈给X [d],如果将它分配给一个变量作为

int h = f | g; 

只用了3毫秒。

我想只将结果赋值给Array,但它大大地妨碍了性能。 这是一个时间关键的程序。

所以我想知道是否有任何替代数组在Java或任何其他方式,我可以避免这种妨碍?

我在默认的Sun JVM配置下测试了这段代码。

P.S.我尝试了不安全的API,但它没有帮助。

+0

使用字典怎么样? – JoeC

+0

你在什么环境下运行,我想知道?那样的结果对我来说似乎不太可能。在Java中测量性能需要您先“预热JVM”;我会三次运行测量并查看第三次穿过它们的数字。 – Gimby

+0

@Gimby - 我也在热身后对它进行了测试,结果非常相似。 – Bull

回答

-1

这是因为h是一个局部变量并分配在堆栈上,而数组存储在主存储器中,写入速度较慢。

另请注意,如果这确实是一个高性能的应用程序,则应该将主逻辑放在for循环中,并避免调用方法的开销。说明可以为你内联,但你不应该依赖它。

+0

这似乎是基于15年前计算机的信息。从那以后事情发生了变化。 – Gimby

+0

堆栈存储器未存储在主存储器中吗?为什么堆栈内存写入比堆内存更快? – Brandon

+0

@Brandon栈变量更可能完全存在于寄存器中。 –

0

你想要提防的是JVM优化代码,因为它没有做任何有用的事情。

在您的情况下,您正在110毫秒或每次通话约1.1纳秒执行1亿次呼叫。鉴于L1缓存访问的单个内存需要4个时钟周期,这非常快。在您的测试中,您在3 ms内获得1亿次,这表明每次通话需要0.03纳秒或约1/10的时钟周期。对我来说这听起来不太可能,我期望如果循环的长度加倍,它仍然需要3毫秒。即您正在计算检测和消除代码需要多长时间。

您遇到的一个基本问题是您有一个大小为400 MB的数组。这不适合L1,L2或L3缓存。相反,它可能会进入主内存,这通常需要200个时钟周期。最好的选择是减少阵列的大小,使其至少适合您的L3缓存。您的L3缓存有多大?如果它是24 MB,请尝试将该阵列减少到16 MB,并且您应该看到性能改进。

0

有很多事情可能发生。首先,尝试连续多次运行您的程序的每个版本并对其进行平均。其次,在Java中分配给数组是一种执行错误检查的方法调用(如必要时抛出ArrayIndexOutOfBoundsException)。这自然会比变量赋值慢一点。如果你有一段非常时间敏感的代码,可以考虑使用JNI进行数字操作:http://docs.oracle.com/javase/6/docs/technotes/guides/jni/。这通常会使您的数组逻辑更快。