繁体   English   中英

Golang追加VS分配内存。 STL push_back内存分配

[英]Golang append memory allocation VS. STL push_back memory allocation

我比较了Go append函数和STL vector.push_back ,发现使我感到困惑的不同内存分配策略。 代码如下:

// CPP STL code
void getAlloc() {
    vector<double> arr;
    int s = 9999999; 
    int precap = arr.capacity();
    for (int i=0; i<s; i++) {
        if (precap < i) {
            arr.push_back(rand() % 12580 * 1.0);
            precap = arr.capacity();
            printf("%d  %p\n", precap, &arr[0]);
        } else {
            arr.push_back(rand() % 12580 * 1.0);
        }
    }
    printf("\n");
    return;
}


// Golang code    
func getAlloc() {
    arr := []float64{}
    size := 9999999
    pre := cap(arr)
    for i:=0; i<size; i++ {
        if pre < i {
            arr = append(arr, rand.NormFloat64())
            pre = cap(arr)
            log.Printf("%d %p\n", pre, &arr)
        } else {
            arr = append(arr, rand.NormFloat64())
        }
    }
    return;
}

但是内存地址对于大小的增加是不变的,这确实让我感到困惑。 顺便说一下,在这两个实现中(STL VS. Go),内存分配策略是不同的,我的意思是扩展大小。 有什么优点或缺点吗? 这是上面代码的简化输出[大小和第一个元素地址]:

Golang                            CPP STL
2 0xc0800386c0                    2  004B19C0
4 0xc0800386c0                    4  004AE9B8
8 0xc0800386c0                    6  004B29E0
16 0xc0800386c0                   9  004B2A18
32 0xc0800386c0                   13  004B2A68
64 0xc0800386c0                   19  004B2AD8
128 0xc0800386c0                  28  004B29E0
256 0xc0800386c0                  42  004B2AC8
512 0xc0800386c0                  63  004B2C20
1024 0xc0800386c0                 94  004B2E20
1280 0xc0800386c0                 141  004B3118
1600 0xc0800386c0                 211  004B29E0
2000 0xc0800386c0                 316  004B3080
2500 0xc0800386c0                 474  004B3A68
3125 0xc0800386c0                 711  004B5FD0
3906 0xc0800386c0                 1066  004B7610
4882 0xc0800386c0                 1599  004B9768
6102 0xc0800386c0                 2398  004BC968
7627 0xc0800386c0                 3597  004C1460
9533 0xc0800386c0                 5395  004B5FD0
11916 0xc0800386c0                8092  004C0870
14895 0xc0800386c0                12138  004D0558
18618 0xc0800386c0                18207  004E80B0
23272 0xc0800386c0                27310  0050B9B0
29090 0xc0800386c0                40965  004B5FD0
36362 0xc0800386c0                61447  00590048
45452 0xc0800386c0                92170  003B0020
56815 0xc0800386c0                138255  00690020
71018 0xc0800386c0                207382  007A0020
....

更新

查看有关Golang内存分配策略的评论。

对于STL,策略取决于实现。 有关更多信息,请参见此帖子

您的Go和C ++代码片段不相同。 在C ++函数中,您将打印矢量中第一个元素的地址,而在Go示例中,您将打印切片本身的地址。

像C ++ std::vector ,Go切片是一种小型数据类型,其中包含指向包含数据的基础数组的指针。 在整个功能中,该数据结构具有相同的地址。 如果需要切片中第一个元素的地址,则可以使用与C ++相同的语法: &arr[0]

您将获得指向切片标头的指针,而不是实际的后备数组。 您可以将slice头视为结构,例如

type SliceHeader struct {
    len,cap int
    backingArray unsafe.Pointer
}

当您追加并重新分配backingArray时,指针backingArray可能会更改(不一定,但可能)。 但是,保存长度,上限和指向后备数组的指针的结构的位置不会更改-仍在声明它的堆栈上。 尝试打印&arr[0]而不是&arr ,您应该会看到行为更接近您的期望。

顺便说一下,这与std::vector几乎是相同的行为。 可以认为切片比魔术动态数组更接近vector

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM