cyb*_*bye 12 java memory performance
我在java中对一个长数组执行了一个简短的基准测试,结果非常奇怪.看起来随机写入的顺序读取比使用顺序写入的随机读取更快 - 一半时间.有谁知道为什么?
以下是两种方法,当按顺序读取时,随机写入一些长整数的数组(使用-Xmx2G左右运行),并在随机写入时按顺序读取:
import java.util.Random;
public class Scratch {
static Random random = new Random();
static long[] arr = new long[100000000];
static void seqReadRandWrite() {
for(int i=0;i<arr.length;i++) {
int at = random.nextInt(arr.length);
arr[at] = arr[i];
}
}
static void seqWriteRandRead() {
for(int i=0;i<arr.length;i++) {
int at = random.nextInt(arr.length);
arr[i] = arr[at];
}
}
public static void main(String[] args) throws Exception {
seqWriteRandRead(); // warm up
long nanos = System.nanoTime();
seqReadRandWrite();
System.out.println("Time: " + (System.nanoTime()-nanos) + "ns");
nanos = System.nanoTime();
seqWriteRandRead();
System.out.println("Time: " + (System.nanoTime()-nanos) + "ns");
}
}
Run Code Online (Sandbox Code Playgroud)
我的笔记本上的结果是
时间:2774662168ns
时间:6059499068ns
这意味着它的随机写入速度是读取的两倍......或者?我的笔记本坏了吗?
ps.:这并不是一个基准,尽管涵盖了关于基准测试的链接建议中的大多数要点.即使我多次运行已经200,000,000次的操作,这些结果仍然保持不变.似乎(似乎!)将内存从随机位置移动到顺序块比将内存从顺序位置移动到随机块更慢,至少使用这种大小的内存和上述方式.我想知道为什么?
综上所述,问题标题略有不正确。事实似乎是,在某些环境(例如我的和OP的)上,随机数组写入比随机数组读取更快。但请注意,对于其他一些人来说,情况并非如此。
根据@JustinKSU 的评论,我将读取和写入分开,发现随机写入比随机读取更快。结果如下。这似乎就是原因,这里的集体意见似乎是缓存上的读取未命中比写入未命中更昂贵(如果写入中涉及任何缓存)。
在生产中,虽然有其他活动,但热点可能会发挥作用。
/cygdrive/c/Java/jdk1.7.0/bin/javac.exe Scratch.java && /cygdrive/c/Java/jdk1.7.0/bin/java Scratch
Starting
seqRead: 1273719725ns
seqRead: 1243055271ns
seqRead: 1245022497ns
seqRead: 1242868527ns
seqRead: 1241655611ns
randRead: 6900959912ns
randRead: 6965196004ns
randRead: 7379623094ns
randRead: 7020390995ns
randRead: 6938997617ns
seqWrite: 1266963940ns
seqWrite: 1250599487ns
seqWrite: 1246471685ns
seqWrite: 1230472648ns
seqWrite: 1246975416ns
randWrite: 3898382192ns
randWrite: 3897441137ns
randWrite: 3939947844ns
randWrite: 4207906037ns
randWrite: 4103594207ns
Compilation finished at Thu Jan 31 14:38:57
Run Code Online (Sandbox Code Playgroud)
我修改后的代码如下:
import java.util.Random;
public class Scratch {
static Random random = new Random();
static long[] arr = new long[100000000];
static void seqReadRandWrite() {
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
arr[at] = arr[i];
}
}
static void seqWriteRandRead() {
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
arr[i] = arr[at];
}
}
static void seqRead() {
int x = 0;
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
x += arr[i];
}
}
static void randRead() {
int x = 0;
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
x += arr[at];
}
}
static void seqWrite() {
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
arr[i] = at;
}
}
static void randWrite() {
for(int i=0;i<arr.length;i++) {
int at = Math.abs(random.nextInt() % arr.length);
arr[at] = at;
}
}
public static void main(String[] args) throws Exception {
// seqWriteRandRead(); // warm up
System.out.println("Starting");
long nanos = -1;
/*
for (int i = 0; i < 5; i++) {
nanos = System.nanoTime();
seqWriteRandRead();
System.out.println("WriteRandRead Time: " + (System.nanoTime()-nanos) + "ns");
nanos = System.nanoTime();
seqReadRandWrite();
System.out.println("ReadRandWrite Time: " + (System.nanoTime()-nanos) + "ns");
}
*/
for (int i = 0; i < 5; i++) {
nanos = System.nanoTime();
seqRead();
System.out.println("seqRead: " + (System.nanoTime()-nanos) + "ns");
}
for (int i = 0; i < 5; i++) {
nanos = System.nanoTime();
randRead();
System.out.println("randRead: " + (System.nanoTime()-nanos) + "ns");
}
for (int i = 0; i < 5; i++) {
nanos = System.nanoTime();
seqWrite();
System.out.println("seqWrite: " + (System.nanoTime()-nanos) + "ns");
}
for (int i = 0; i < 5; i++) {
nanos = System.nanoTime();
randWrite();
System.out.println("randWrite: " + (System.nanoTime()-nanos) + "ns");
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新
@tomcarchrae 在 Linux 上做了相同的测试,但结果明显不同。下面,第一列是我测试的数字,第二列来自汤姆的测试:
seqRead: 1273719725ns 2810487542ns
seqRead: 1243055271ns 2780504580ns
seqRead: 1245022497ns 2746663894ns
seqRead: 1242868527ns 2746094469ns
seqRead: 1241655611ns 2763107970ns
randRead: 6900959912ns 23093543703ns
randRead: 6965196004ns 22458781637ns
randRead: 7379623094ns 24421031646ns
randRead: 7020390995ns 25880250599ns
randRead: 6938997617ns 26873823898ns
seqWrite: 1266963940ns 4226886722ns
seqWrite: 1250599487ns 4537680602ns
seqWrite: 1246471685ns 3880372295ns
seqWrite: 1230472648ns 4160499114ns
seqWrite: 1246975416ns 4008607447ns
randWrite: 3898382192ns 25985349107ns
randWrite: 3897441137ns 22259835568ns
randWrite: 3939947844ns 22556465742ns
randWrite: 4207906037ns 22143959163ns
randWrite: 4103594207ns 21737397817ns
Run Code Online (Sandbox Code Playgroud)