Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.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
C 阵列性能与LinkedList非常相似-提供了什么?_C_Arrays_Performance_Unix_Linked List - Fatal编程技术网

C 阵列性能与LinkedList非常相似-提供了什么?

C 阵列性能与LinkedList非常相似-提供了什么?,c,arrays,performance,unix,linked-list,C,Arrays,Performance,Unix,Linked List,所以这个标题有点误导。。。我将保持简单:我将比较这两种数据结构: 一个数组,它从大小1开始,对于随后的每次添加,都有一个realloc()调用来扩展内存,然后将新的(malloced)元素附加到n-1位置 一个链表,用来记录头部、尾部和大小。此外,还涉及新元素的mallocing和更新尾部指针和大小 不要担心这些数据结构的任何其他细节。这是我在测试中唯一关心的功能 理论上,LL的表现应该更好。然而,他们在涉及10,100,1000的时间测试中几乎相同。。。多达5000000个元素 我的直觉是这堆

所以这个标题有点误导。。。我将保持简单:我将比较这两种数据结构:

  • 一个数组,它从大小1开始,对于随后的每次添加,都有一个realloc()调用来扩展内存,然后将新的(malloced)元素附加到n-1位置

  • 一个链表,用来记录头部、尾部和大小。此外,还涉及新元素的mallocing和更新尾部指针和大小
  • 不要担心这些数据结构的任何其他细节。这是我在测试中唯一关心的功能

    理论上,LL的表现应该更好。然而,他们在涉及10,100,1000的时间测试中几乎相同。。。多达5000000个元素

    我的直觉是这堆东西很大。我认为Redhat上的数据段默认为10MB?我可能错了。无论如何,realloc()首先检查已分配的连续内存位置(0-[n-1])的末尾是否有可用空间。如果第n个位置可用,则不会重新定位图元。相反,realloc()只保留旧空间+紧跟其后的空间。我很难找到这方面的证据,也很难证明这个数组在实践中的性能应该比LL差

    在阅读了下面的帖子后,下面是一些进一步的分析:

    [更新#1] 我已经修改了代码,为LL和数组提供了一个单独的列表,每50次迭代mallocs内存。对于阵列中的100万个新成员,几乎一致地有18个移动。没有为LL搬家的概念。我做了一个时间比较,它们仍然几乎相同。以下是1000万新增项目的一些产出:

    (Array)
    time ./a.out a 10,000,000
    real    0m31.266s
    user    0m4.482s
    sys     0m1.493s
    (LL)
    time ./a.out l 10,000,000
    real    0m31.057s
    user    0m4.696s
    sys     0m1.297s
    
    我预计这18个动作的时机会大不相同。数组添加需要再进行1次赋值和1次比较,以获取并检查realloc的返回值,以确保发生移动

    [更新#2] 我在上面发布的测试中运行了ltrace,我认为这是一个有趣的结果。。。看起来realloc(或某些内存管理器)正在基于当前大小抢占式地将阵列移动到更大的连续位置。 对于500次迭代,在迭代时触发内存移动: 1, 2, 4, 7, 11, 18, 28, 43, 66, 101, 154, 235, 358 这非常接近于求和序列。我觉得这很有趣——我想我会把它贴出来。(更新) 正如其他人所指出的,如果realloc之间没有其他分配,则不需要复制。正如其他人所指出的,对于比页面小的非常小的块,内存复制的风险会降低(当然也会降低其影响)

    此外,如果您在测试中所做的只是分配新的内存空间,那么我并不感到惊讶,因为分配内存的系统调用可能占用了大部分时间

    相反,根据实际使用数据结构的方式选择数据结构。例如,帧缓冲区可能最好由连续数组表示

    如果必须在结构中快速重新组织或排序数据,则链表可能更好

    那么,这些操作的效率将取决于您想要做什么


    (感谢下面的评论,一开始我对这些东西是如何工作的感到困惑。)

    你的理论基础是什么,链表应该在最后的插入中表现得更好?我不希望它会这样,因为正是你所说的原因
    realloc
    仅在必须保持连续性时才进行复制;在其他情况下,它可能必须组合空闲块和/或增加块大小

    但是,每个链表节点都需要新的分配和(假设为双链表)两次写入。如果您想了解
    realloc
    的工作原理,只需比较
    realloc
    前后的指针即可。你应该发现它通常不会改变

    我怀疑,由于您正在为每个元素调用
    realloc
    (在生产中显然不明智),因此
    realloc
    /
    malloc
    调用本身是这两个测试的最大瓶颈,即使
    realloc
    通常不提供新指针


    此外,您还混淆了堆和数据段。堆是malloced内存所在的位置。数据段用于全局变量和静态变量。

    那么您正在测试数组相对于链表的扩展速度

    在这两种情况下,您都在调用内存分配函数。通常,内存分配函数从操作系统中获取一块内存(可能是一页),然后根据应用程序的需要将其分成更小的部分


    另一个假设是,realloc()有时会抛出虚拟内存并在其他地方分配一大块内存,因为它无法在当前分配的页面中获得连续的内存块。如果在列表展开之间没有对内存分配函数进行任何其他调用,则不会发生这种情况。也许操作系统对虚拟内存的使用意味着无论物理页来自何处,程序堆都在不断扩展。在这种情况下,性能将与一系列malloc()调用相同


    当您混合使用malloc()和realloc()调用时,性能会发生变化。

    您是对的,realloc只会增加分配块的大小,除非阻止它这样做。在真实场景中,在列表的后续添加之间,很可能会在堆上分配其他对象?在这种情况下,realloc必须分配一个全新的内存块,并复制列表中已有的元素

    尝试在堆上使用malloc为大约每十次插入分配另一个对象,看看它们是否仍然存在