如何计算c++中类对象使用的内存量?
How do I calculate the amount of memory a class object uses in C++?
我想以字节为单位计算对象使用的内存量。鉴于
struct A
{
float data[16];
int index;
};
struct B
{
A a;
};
下面的方法是正确的吗?
template <class Type>
size_t footprint();
template <>
size_t footprint<A>()
{
return sizeof(float) * 16 + sizeof(int);
}
template <>
size_t footprint<B>()
{
return footprint<A>();
}
我不确定关于footprint(),因为我听说编译器可能会添加额外的信息只是为了存储成员变量,我不确定关于footprint(),因为它引用一个类对象。这也需要一些内存吗?
编辑:好的,假设情况发生了变化,我们不再使用静态数组,而是使用实际指针:#include <iostream>
using namespace std;
struct A
{
A(int size_)
{
data = new float[size_];
size = size_;
}
~A()
{
delete [] data;
}
float* data;
int size;
};
struct B
{
B() : a(16) {}
A a;
};
size_t footprint(const A& a)
{
return sizeof(float) * a.size + sizeof(int);
}
size_t footprint(const B& b)
{
return footprint(b.a);
}
int main()
{
A a(16);
B b;
cout << "sizeof(A) = " << sizeof(A) << endl;
cout << "sizeof(B) = " << sizeof(B) << endl;
cout << "footprint(a) = " << footprint(a) << endl;
cout << "footprint(b) = " << footprint(b) << endl;
}
这里你需要一个特殊的sizeof函数(这里叫做footprint),对吧?
正确的方法是使用sizeof(A)
或sizeof(B)
。将成员的大小相加是不正确的,因为编译器可以自由地放入额外的空间,称为填充,以正确对齐。sizeof
占这个填充。
您还表达了对数组衰变成指针的担忧。这与sizeof
不同。sizeof(an array)
将给出该数组占用的总字节数,前提是它仍然是数组形式并且没有衰减为指针。事实是,标准明确禁止在sizeof
中发生这种衰减,所以您在那里是安全的:
c++ 11 N3485§5.3.3/4:
左值到右值的标准转换(4.1)、数组到指针的标准转换(4.2)和函数到指针的标准转换(4.3)则不是适用于sizeof.
的操作数
sizeof(A) == 16 * sizeof(float) + sizeof(int) + sizeof(additional padding)
因为这个例子有一个静态分配的数组,那么使用sizeof(a)会给你正确的大小。但是,由于位填充的原因,有时大小会与您期望的不同。
然而,如果你有动态分配的数组,你需要这样做:
lengthOfArray*sizeof(arrayElement);
不仅是return sizeof(float) * 16 + sizeof(int);
相当麻烦的更复杂的对象,但也可能是不正确的。C语言规范允许编译器"填充"结构。例如,我们有
class X {
public:
int i;
char c;
double d;
};
你调整结构大小的方法会说它占用4 + 1 + 8(或类似的),但实际的sizeof(X)
会给4 + 4 + 8。在小型和大型数据类型极端混合的情况下,我们很容易看到50-75%的误差。[成员的确切布局取决于编译器、处理器架构、编译器开关等]。
在动态分配情况下,情况变得复杂得多。实际考虑类使用情况的最佳解决方案是实现自己的操作符::new(size_t size)[并可能调用malloc来分配size的字节数],然后考虑大小-然而,这不会考虑分配器本身的开销,每次调用new都会增加12个字节以上的开销。分配器也可以将实际分配的大小四舍五入。
作为前面答案的补充,编译器为您提供了控制填充行为的方法(因此您可以对sizeof(A)产生影响,如果内存占用在程序的那个点对您特别重要,如果您想通过网络发送您的结构,或其他)。
您可以查看#pragma pack
语句以实现此目标。
我还没有看到一个问题被提到。当你做
float * data = new float[size_];
delete [] data;
则sizeof(float) * size_是分配的内存量。但是当你这样做
std::string * data = new std::string[size_];
delete [] data;
在执行delete操作时,需要知道new()操作期间size_的值,以便知道调用std::string析构函数的次数。c++有时可以在分配中添加几个字节,以跟踪您分配了多少数组成员。
根据上面的评论,我认为需要另一个答案。
我可以想到一些很好的解决方案来限制缓存使用的内存量:1. 每天开始时,分配X KB的内存(无论您的缓存"允许"使用多少)。根据需要把它切成几段。满了之后,取出最旧的并重复使用(如果它们的大小不同,可能需要多个)。
你需要一些方法来标记"最近使用的"或"旧的",这样你就可以扔掉最旧的东西。可能是通过使用一个自动重新排序当你获取一些东西,最近的对象在树的顶部。
-
与上面类似,但是使用固定数量的固定大小的数据块-例如16或32(或256,或500或任何对典型缓存条目大小最有意义的东西)。在一天开始时,将所有缓存条目放入"空闲"容器(例如列表)。当您需要一个新的缓存条目时,获取空闲列表的顶部。如果列表为空,则查找最老的列表并将其重用到缓存中。
-
如果您存储的对象类型和大小不同,您可能会发现创建自己的堆,并为您的类使用operator::new()是更好的选择(显然还有相应的operator::delete())。对于如何创建自己的堆(在c++中有时称为自由存储),有多种解决方案。我更倾向于用有限尺寸的子弹,这样就不会有这么严重的碎片。
- 迭代时从向量和内存中删除对象
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- Constexpr替代了新的放置方式,可以让内存中的对象保持未初始化状态
- 对具有动态分配的内存和析构函数的类对象的引用
- 当指向对象的指针作为参数传递给 std::thread 时,内存可见性
- 内存清理程序报告全局对象构造中未初始化值的使用
- 如何删除列出的"QGraphicsPathItem"对象以控制进程内存使用情况?
- 准确了解对象在内存中的映射方式
- 完全释放静态对象内存
- C++ 对象内存管理
- 循环中的自动变量和自动对象内存分配
- 每个对象内存分配有多少开销
- 是隐式创建的默认构造函数,负责分配对象内存
- 使用 make_unique 语句重新分配unique_ptr对象 - 内存泄漏
- C++对象内存布局
- C++对象内存消耗
- 谷歌模拟全局模拟对象内存泄漏
- 静态工厂方法和静态对象内存泄漏
- 关于对象内存布局的假设
- 如果我在管理C++对象内存的目标 C 中混合C++代码,ARC 会处理它