【问题标题】:Memory usage for arrays and vectors (64 bit)?数组和向量的内存使用情况(64 位)?
【发布时间】:2020-03-24 05:57:33
【问题描述】:

我正在存储大量数据并希望优化内存。我感到困惑的是以下(编译64位):

char a[10] = {1,2,3,4,5,6,7,8,9,10};
long long int b[10] = {1,2,3,4,5,6,7,8,9,10};
vector<char> x = vector<char>(10,0);
vector<long long int> y = vector<long long int>(10,0);
cout << sizeof(a) <<" "<< sizeof(b)<< " " <<sizeof(x) <<" "<< sizeof(y)<< endl;

打印值 10 80 24 24。

1) char[10] 实际上只使用 10 个字节吗?它不应该使用 80 字节吗,因为在 64 位编译中,内存只能针对 64 位块进行寻址?

2)最后两行:为什么是24(3个字节?)仅仅是vector的结构包含24个字节的数据吗?

3) 包含 1000 个元素的字符向量是否与包含 1000 个元素的 long long int 向量使用相同的内存量?

【问题讨论】:

  • 前两个是静态数组,内存是在栈上分配的。 Vectors 在堆上分配内存并指向它。数组的大小是指针的大小加上一些元数据

标签: c++ sizeof


【解决方案1】:

1) 一个字符是一个单字节。只是因为您使用的是 64 位系统(这意味着它可以使用 64 位地址寻址单个字节,而不是一次只能读取/写入 64 位)。我认为您可能会混淆缓存行和内存读取。从内存中读取单个字节,一般会取出 64 个字节作为缓存行。与是否访问 1 个字节无关。

2) sizeof 返回大小以字节为单位,而不是以位为单位。 std::vector 通常实现为 3 个指针的结构,一个用于开始、结束和容量:

struct vector
{
  int* begin;
  int* end;
  int* capacity;
};

由于这是一个 64 位系统,您的指针值 (addresses) 将是 8 字节 (== 64bit)。因此,sizeof 3xpointer 值将是 24 (3 * sizeof(void*))

无论您在向量中存储何种数据类型,sizeof 将始终返回 24(在典型的 64 位架构上)

3) sizeof 只计算数据结构的原始大小。它没有考虑到该结构内的指针值具有一些额外的动态分配内存的事实。要获得完整的尺寸,需要这样的东西:

template<typename T>
size_t getUsedMemUsage(const std::vector<T>& vec)
{
  size_t size_of_vector_struct = sizeof(std::vector<T>);
  size_t size_of_single_element = sizeof(T);
  return size_of_vector_struct + size_of_single_element * vec.size();
}
template<typename T>
size_t getFullMemUsage(const std::vector<T>& vec)
{
  size_t size_of_vector_struct = sizeof(std::vector<T>);
  size_t size_of_single_element = sizeof(T);
  return size_of_vector_struct + size_of_single_element * vec.capacity();
}

尽管严格来说这不是真的(例如,操作系统可能会使用一些额外的字节来对齐内存分配,并且可能使用 ~16 字节来跟踪分配)

所以不,1000 个 long long int 的向量将比 1000 个字符的向量使用更少的内存(大约为 sizeof(long long int) / sizeof(char)

【讨论】:

    【解决方案2】:

    首先要搞清楚data model使用的是哪个,各种数据类型占用了多少内存。

    1. 数组数据占用一个连续的内存区域,而不会发生对齐,因为所有元素都属于同一类型。所以char[10] 的大小为 10 * 1 = 10 字节。
    2. std::vector 在堆上分配内存,也就是说,它只存储一个指向已分配内存的指针,而不存储元素本身。 std::vector 本身只存储一个指向已分配内存的指针、已分配内存的大小和元素的数量。指针的大小是 8 字节,其他元素的大小通常也是 8 字节,所以sizeof(std::vector&lt;...&gt;),无论数据类型如何,都是8 + 8 + 8 = 24 字节。
    3. 实际上我在上面回答了这个问题。 sizeof(std::vector&lt;...&gt;) 实际上与数据类型无关。相反,堆上分配的内存大小取决于数据类型。 std::vector&lt;long long&gt;(1000)std::vector&lt;char&gt;(1000) 消耗更多的内存。

    【讨论】:

      最近更新 更多