Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java虚拟机上的阵列分配和访问与内存争用_Java_Arrays_Memory_Memory Management_Concurrency - Fatal编程技术网

Java虚拟机上的阵列分配和访问与内存争用

Java虚拟机上的阵列分配和访问与内存争用,java,arrays,memory,memory-management,concurrency,Java,Arrays,Memory,Memory Management,Concurrency,遵循以下线程子类的定义(为了方便起见,问题末尾包含了整个可运行Java源文件): 案例1:1,2,4,8线程的运行时间,顺序为(7次重复): 我的想法是,非线性缩放是由于内存争用。顺便说一句,早期迭代实际上做得更好——这可能是因为在不同的迭代中,数组被分配到不同的内存区域 案例2:接下来,我在线程的run方法中注释Foo[]arr=array行,并在run方法本身中分配一个新数组:Foo[]arr=new Foo[1024]。测量: >>> All running times:

遵循以下线程子类的定义(为了方便起见,问题末尾包含了整个可运行Java源文件):

案例1:
1,2,4,8
线程的运行时间,顺序为(7次重复):

我的想法是,非线性缩放是由于内存争用。顺便说一句,早期迭代实际上做得更好——这可能是因为在不同的迭代中,数组被分配到不同的内存区域

案例2:接下来,我在线程的
run
方法中注释
Foo[]arr=array
行,并在
run
方法本身中分配一个新数组:
Foo[]arr=new Foo[1024]
。测量:

>>> All running times: [2053, 1966, 2089, 1937, 2046, 1909, 2011]
>>> All running times: [1048, 1178, 1100, 1194, 1367, 1271, 1207]
>>> All running times: [578, 508, 589, 571, 617, 643, 645]
>>> All running times: [330, 299, 300, 322, 331, 324, 575]
这一次,一切的规模几乎和预期的一样。我没有想到分配数组的位置会起到任何作用,但很明显,它确实起到了作用。我的想法是,以前分配的阵列彼此非常接近,以至于开始发生内存争用

案例3:为了验证这一假设,我再次取消了对行
Foo[]arr=array
的注释,但这次将
array
字段初始化为
new Foo[32000]
,以确保写入的内存中的位置彼此之间足够远。因此,这里我们再次使用在创建thread对象期间分配的数组,与CASE1的区别只是数组更大

>>> All running times: [2113, 1983, 2430, 2485, 2333, 2359, 2463]
>>> All running times: [1172, 1106, 1163, 1181, 1142, 1169, 1188]
>>> All running times: [578, 677, 614, 604, 583, 637, 597]
>>> All running times: [343, 327, 320, 330, 353, 320, 320]
因此,内存争用似乎是造成这种情况的原因

平台信息:

Ubuntu Server 10.04.3 LTS
8 core Intel(R) Xeon(R) CPU  X5355  @2.66GHz
~20GB ram
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)
问题:这显然是内存争用问题。但为什么会这样

  • 逃逸分析开始了吗?如果是这样,是否意味着在案例2中的
    run
    方法中创建时,整个数组都在堆栈上分配?此运行时优化的确切条件是什么?肯定没有在堆栈上为100万个元素分配数组吗

  • 即使阵列是在堆栈上分配的,而不是在 堆,不同线程的两个数组访问应该至少除以512*4bytes=2kb,即使在案例1中,无论数组在哪里!这肯定比任何一级缓存线都大。如果这些影响是由于错误共享造成的,那么写入几个完全独立的缓存线如何对性能产生如此大的影响?(这里的一个假设是,每个阵列占用JVM上的一个连续内存块,该内存块在创建阵列时分配。我不确定这是否有效。另一个假设是,阵列写入不会一直到内存,而是一级缓存,因为Intel Xeon确实有一个ccNUMA体系结构-如果我错了,请纠正我)

  • 是否每个线程都有自己的本地堆部分,在那里它独立地分配新对象,这是在线程中分配阵列时争用较低的原因?如果是这样的话,如果引用被共享,堆垃圾区域是如何收集的

  • 为什么将阵列大小增加到约32000个元素会提高可伸缩性(减少内存争用)?内存层次结构中到底是什么导致了这种情况

  • 请准确无误,并用参考资料支持您的主张

    谢谢大家!


    整个可运行Java程序:

    import java.util.ArrayList;
    
    class MultiStackJavaExperiment {
    
        final class Foo {
            int x = 0;
        }
    
        final class Worker extends Thread {
            Foo[] array = new Foo[1024];
            int sz;
    
            public Worker(int _sz) {
                sz = _sz;
            }
    
            public void run() {
                Foo[] arr = new Foo[1024];
                //Foo[] arr = array;
                loop(arr);
            }
    
            public void loop(Foo[] arr) {
                int i = 0;
                int pos = 512;
                Foo v = new Foo();
                while (i < sz) {
                    if (i % 2 == 0) {
                        arr[pos] = v;
                        pos += 1;
                    } else {
                        pos -= 1;
                        v = arr[pos];
                    }
                    i++;
                }
            }
        }
    
        public static void main(String[] args) {
            (new MultiStackJavaExperiment()).mainMethod(args);
        }
    
        int size = Integer.parseInt(System.getProperty("size"));
        int par = Integer.parseInt(System.getProperty("par"));
    
        public void mainMethod(String[] args) {
            int times = 0;
            if (args.length == 0) times = 1;
            else times = Integer.parseInt(args[0]);
            ArrayList < Long > measurements = new ArrayList < Long > ();
    
            for (int i = 0; i < times; i++) {
                long start = System.currentTimeMillis();
                run();
                long end = System.currentTimeMillis();
    
                long time = (end - start);
                System.out.println(i + ") Running time: " + time + " ms");
                measurements.add(time);
            }
    
            System.out.println(">>>");
            System.out.println(">>> All running times: " + measurements);
            System.out.println(">>>");
        }
    
        public void run() {
            int sz = size / par;
            ArrayList < Thread > threads = new ArrayList < Thread > ();
    
            for (int i = 0; i < par; i++) {
                threads.add(new Worker(sz));
                threads.get(i).start();
            }
            for (int i = 0; i < par; i++) {
                try {
                    threads.get(i).join();
                } catch (Exception e) {}
            }
        }
    
    }
    
    import java.util.ArrayList;
    课堂教学实验{
    最后一节课Foo{
    int x=0;
    }
    最后一个类辅助程序扩展线程{
    Foo[]数组=新Foo[1024];
    int sz;
    公共工作者(内华达州){
    sz=_sz;
    }
    公开募捐{
    Foo[]arr=新Foo[1024];
    //Foo[]arr=数组;
    环路(arr);
    }
    公共无效循环(Foo[]arr){
    int i=0;
    int pos=512;
    Foo v=新的Foo();
    而(i测量值=新的ArrayList();
    for(int i=0;i>>”);
    System.out.println(“>>>所有运行时间:“+测量值”);
    System.out.println(“>>>”);
    }
    公开募捐{
    INSZ =大小/PAR;
    ArrayListthreads=新的ArrayList();
    对于(int i=0;i<PAR;i++){
    添加(新工作线程(sz));
    threads.get(i.start();
    }
    对于(int i=0;i<PAR;i++){
    试一试{
    threads.get(i.join();
    }捕获(例外e){}
    }
    }
    }
    
    我认为你需要减少你的代码,这样它就不会做很多可能会让人困惑的事情。在减少代码之后,我很清楚,您每次只访问相同的数组位置。i、 e.位置512

    如果你最小化了你的代码,重用你的线程,这样你就不会停止/启动它们,你会得到更多可重复的结果

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class MultiStackJavaExperiment {
        static final int size = Integer.getInteger("size", 500000000);
    
        public static void main(String... args) throws ExecutionException, InterruptedException {
            int par = 8;
            for (int s = 64; s <= 64 * 1024; s *= 2) {
                int times = args.length == 0 ? 1 : Integer.parseInt(args[0]);
                long[] measurements = new long[times];
    
                ExecutorService es = Executors.newFixedThreadPool(par);
                List<Future<?>> futures = new ArrayList<Future<?>>(times);
                for (int i = 0; i < times; i++) {
                    long start = System.currentTimeMillis();
                    final int sz = size / par;
                    futures.clear();
                    for (int j = 0; j < par; j++) {
                        final Object[] arr = new Object[s];
                        futures.add(es.submit(new Runnable() {
                            @Override
                            public void run() {
                                final int bits = 7, arraySize = 1 << bits;
                                int i = 0;
                                int pos = 32;
                                Object v = new Object();
                                while (i < sz) {
                                    if (i % 2 == 0) {
                                        arr[pos] = v;
                                        pos += 1;
                                    } else {
                                        pos -= 1;
                                        v = arr[pos];
                                    }
                                    i++;
                                }
                            }
                        }));
                    }
                    for (Future<?> future : futures)
                        future.get();
    
                    long time = System.currentTimeMillis() - start;
    //                System.out.println(i + ") Running time: " + time + " ms");
                    measurements[i] = time;
                }
                es.shutdown();
                System.out.println("par = " + par + " arr.length= "+ s  + " >>> All running times: " + Arrays.toString(measurements));
            }
        }
    }
    
    如果将数组移动到线程内,则会得到

    par = 8 arr.length= 64 >>> All running times: [225, 151, 151, 150, 152, 153, 152]
    par = 8 arr.length= 256 >>> All running times: [155, 151, 151, 151, 151, 151, 155]
    par = 8 arr.length= 1024 >>> All running times: [153, 152, 151, 151, 151, 155, 152]
    par = 8 arr.length= 4096 >>> All running times: [155, 156, 151, 152, 151, 155, 155]
    par = 8 arr.length= 16384 >>> All running times: [154, 157, 152, 152, 158, 153, 153]
    par = 8 arr.length= 65536 >>> All running times: [155, 157, 152, 184, 181, 154, 153]
    par = 8 arr.length= 262144 >>> All running times: [240, 159, 166, 151, 172, 154, 160]
    par = 8 arr.length= 1048576 >>> All running times: [165, 162, 163, 162, 163, 162, 163]
    
    关闭tlab w
    import java.util.ArrayList;
    
    class MultiStackJavaExperiment {
    
        final class Foo {
            int x = 0;
        }
    
        final class Worker extends Thread {
            Foo[] array = new Foo[1024];
            int sz;
    
            public Worker(int _sz) {
                sz = _sz;
            }
    
            public void run() {
                Foo[] arr = new Foo[1024];
                //Foo[] arr = array;
                loop(arr);
            }
    
            public void loop(Foo[] arr) {
                int i = 0;
                int pos = 512;
                Foo v = new Foo();
                while (i < sz) {
                    if (i % 2 == 0) {
                        arr[pos] = v;
                        pos += 1;
                    } else {
                        pos -= 1;
                        v = arr[pos];
                    }
                    i++;
                }
            }
        }
    
        public static void main(String[] args) {
            (new MultiStackJavaExperiment()).mainMethod(args);
        }
    
        int size = Integer.parseInt(System.getProperty("size"));
        int par = Integer.parseInt(System.getProperty("par"));
    
        public void mainMethod(String[] args) {
            int times = 0;
            if (args.length == 0) times = 1;
            else times = Integer.parseInt(args[0]);
            ArrayList < Long > measurements = new ArrayList < Long > ();
    
            for (int i = 0; i < times; i++) {
                long start = System.currentTimeMillis();
                run();
                long end = System.currentTimeMillis();
    
                long time = (end - start);
                System.out.println(i + ") Running time: " + time + " ms");
                measurements.add(time);
            }
    
            System.out.println(">>>");
            System.out.println(">>> All running times: " + measurements);
            System.out.println(">>>");
        }
    
        public void run() {
            int sz = size / par;
            ArrayList < Thread > threads = new ArrayList < Thread > ();
    
            for (int i = 0; i < par; i++) {
                threads.add(new Worker(sz));
                threads.get(i).start();
            }
            for (int i = 0; i < par; i++) {
                try {
                    threads.get(i).join();
                } catch (Exception e) {}
            }
        }
    
    }
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class MultiStackJavaExperiment {
        static final int size = Integer.getInteger("size", 500000000);
    
        public static void main(String... args) throws ExecutionException, InterruptedException {
            int par = 8;
            for (int s = 64; s <= 64 * 1024; s *= 2) {
                int times = args.length == 0 ? 1 : Integer.parseInt(args[0]);
                long[] measurements = new long[times];
    
                ExecutorService es = Executors.newFixedThreadPool(par);
                List<Future<?>> futures = new ArrayList<Future<?>>(times);
                for (int i = 0; i < times; i++) {
                    long start = System.currentTimeMillis();
                    final int sz = size / par;
                    futures.clear();
                    for (int j = 0; j < par; j++) {
                        final Object[] arr = new Object[s];
                        futures.add(es.submit(new Runnable() {
                            @Override
                            public void run() {
                                final int bits = 7, arraySize = 1 << bits;
                                int i = 0;
                                int pos = 32;
                                Object v = new Object();
                                while (i < sz) {
                                    if (i % 2 == 0) {
                                        arr[pos] = v;
                                        pos += 1;
                                    } else {
                                        pos -= 1;
                                        v = arr[pos];
                                    }
                                    i++;
                                }
                            }
                        }));
                    }
                    for (Future<?> future : futures)
                        future.get();
    
                    long time = System.currentTimeMillis() - start;
    //                System.out.println(i + ") Running time: " + time + " ms");
                    measurements[i] = time;
                }
                es.shutdown();
                System.out.println("par = " + par + " arr.length= "+ s  + " >>> All running times: " + Arrays.toString(measurements));
            }
        }
    }
    
    par = 8 arr.length= 64 >>> All running times: [539, 413, 444, 444, 457, 444, 456]
    par = 8 arr.length= 256 >>> All running times: [398, 527, 514, 529, 445, 441, 445]
    par = 8 arr.length= 1024 >>> All running times: [419, 507, 477, 422, 412, 452, 396]
    par = 8 arr.length= 4096 >>> All running times: [316, 282, 250, 232, 242, 229, 238]
    par = 8 arr.length= 16384 >>> All running times: [316, 207, 209, 212, 208, 208, 208]
    par = 8 arr.length= 65536 >>> All running times: [211, 211, 208, 208, 208, 291, 206]
    par = 8 arr.length= 262144 >>> All running times: [366, 210, 210, 210, 210, 209, 211]
    par = 8 arr.length= 1048576 >>> All running times: [296, 211, 215, 216, 213, 211, 211]
    
    par = 8 arr.length= 64 >>> All running times: [225, 151, 151, 150, 152, 153, 152]
    par = 8 arr.length= 256 >>> All running times: [155, 151, 151, 151, 151, 151, 155]
    par = 8 arr.length= 1024 >>> All running times: [153, 152, 151, 151, 151, 155, 152]
    par = 8 arr.length= 4096 >>> All running times: [155, 156, 151, 152, 151, 155, 155]
    par = 8 arr.length= 16384 >>> All running times: [154, 157, 152, 152, 158, 153, 153]
    par = 8 arr.length= 65536 >>> All running times: [155, 157, 152, 184, 181, 154, 153]
    par = 8 arr.length= 262144 >>> All running times: [240, 159, 166, 151, 172, 154, 160]
    par = 8 arr.length= 1048576 >>> All running times: [165, 162, 163, 162, 163, 162, 163]
    
    par = 8 arr.length= 64 >>> All running times: [608, 467, 467, 457, 468, 461, 428]
    par = 8 arr.length= 256 >>> All running times: [437, 437, 522, 512, 522, 369, 535]
    par = 8 arr.length= 1024 >>> All running times: [394, 395, 475, 525, 470, 440, 478]
    par = 8 arr.length= 4096 >>> All running times: [347, 215, 238, 226, 236, 204, 271]
    par = 8 arr.length= 16384 >>> All running times: [291, 157, 178, 151, 150, 151, 152]
    par = 8 arr.length= 65536 >>> All running times: [163, 152, 162, 151, 159, 159, 154]
    par = 8 arr.length= 262144 >>> All running times: [164, 172, 152, 169, 160, 161, 160]
    par = 8 arr.length= 1048576 >>> All running times: [295, 153, 164, 153, 166, 154, 163]