类中的内存使用情况 - 将双精度转换为浮点数并未按预期减少内存使用量
memory usage of in class - converting double to float didn't reduce memory usage as expected
我正在初始化数百万个以下类型的类
template<class T>
struct node
{
//some functions
private:
T m_data_1;
T m_data_2;
T m_data_3;
node* m_parent_1;
node* m_parent_2;
node* m_child;
}
模板的目的是使用户能够选择float
或double
精度,其思想是node<float>
将占用更少的内存(RAM)。
然而,当我从double
切换到float
时,我的程序的内存占用并没有像我期望的那样减少。我有两个问题,
是否有可能编译器/操作系统为我的浮点数保留了比所需更多的空间(甚至将它们存储为双精度)?如果是这样,我如何阻止这种情况发生-我在64位机器上使用linux和g++。
是否有一个工具可以让我确定所有不同类使用的内存量?(即某种内存分析)-以确保内存没有被谷歌在其他地方,我没有想到。
如果编译为64位,则每个指针的大小将为64位。这也意味着它们可能需要对齐到64位。所以如果你存储3个浮点数,它可能需要插入4个字节的填充。所以不是12个字节,而是8个字节。无论指针是在结构体的开始还是结束,填充仍然存在。这是必要的,以便将连续的结构体放入数组中以继续保持对齐。
同样,你的结构主要由3个指针组成。您节省的8个字节将您从一个48字节的对象变成一个40字节的对象。这并不是一个很大的下降。同样,如果您正在编译64位。
如果你编译为32位,那么你从一个36字节的结构中节省了12个字节,这是更好的百分比。如果double必须对齐为8字节,则可能更多。
关于差异的来源,其他答案都是正确的。然而,x86/x86-64上的指针(和其他类型)是不需要对齐的。只是当它们对齐时性能会更好,这就是为什么GCC默认保持它们对齐的原因。
但是GCC提供了一个"packed"属性来让你控制它:
#include <iostream>
template<class T>
struct node
{
private:
T m_data_1;
T m_data_2;
T m_data_3;
node* m_parent_1;
node* m_parent_2;
node* m_child;
} ;
template<class T>
struct node2
{
private:
T m_data_1;
T m_data_2;
T m_data_3;
node2* m_parent_1;
node2* m_parent_2;
node2* m_child;
} __attribute__((packed));
int
main(int argc, char *argv[])
{
std::cout << "sizeof(node<double>) == " << sizeof(node<double>) << std::endl;
std::cout << "sizeof(node<float>) == " << sizeof(node<float>) << std::endl;
std::cout << "sizeof(node2<float>) == " << sizeof(node2<float>) << std::endl;
return 0;
}
在我的系统(x86-64, g++ 4.5.2)上,这个程序输出:
sizeof(node<double>) == 48
sizeof(node<float>) == 40
sizeof(node2<float>) == 36
当然,"attribute"机制和"packed"属性本身是gcc特有的。
除了Nicol提出的有效观点之外:
当你调用new/malloc时,它不一定与操作系统分配内存的调用对应1对1。这是因为为了减少昂贵的系统调用的数量,堆管理器可能会分配比请求的更多的内存,然后在调用new/malloc时"子分配"其中的块。此外,每次只能分配4kb内存(通常情况下,这是最小页面大小)。从本质上讲,为了加快未来的分配速度,可能会分配一些当前未被积极使用的内存块。
直接回答你的问题:
1)是的,运行时很可能会分配更多的内存,然后你要求-但这些内存不会浪费,它将用于未来的新闻/malloc,但仍然会出现在"任务管理器"或任何你使用的工具。不,它不会将float提升为double。你做的分配越多,这种边缘条件就越不可能导致尺寸差异,而Nicol的项目将占主导地位。对于较小数量的分配,该项可能占主导地位(其中"大"answers"小"完全取决于您的操作系统和内核)。
2) windows任务管理器会给你分配的总内存。像WinDbg这样的东西实际上会给你由运行时分配的虚拟内存范围块(通常在树中分配)。对于Linux,我希望这些数据将在与您的进程相关联的/proc目录中的一个文件中可用。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 使用提升将数据从 PyObject 复制到浮点数 *
- 使用浮点数和双精度数的非常小数字的数学
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 如何在 c++ 中将小数点后两位数的浮点数分配给另一个浮点数
- 返回浮点数的小数位数
- txt 文件中浮点数的最大和最小值
- 为什么 std::cout 打印浮点数、双精度和长双精度到相同的小数精度?
- 将浮点数转换为无符号字符数组并打印出来
- 如何将时间字符串 (M:SS) 转换为浮点数
- 需要在内存C++中放置一个浮点数作为十六进制
- 为浮点数组动态分配内存
- 我可以在CUDA设备上为包含浮点数数组的对象分配内存吗
- 什么是最大内存可以分配给浮点数的 C++ 向量
- 将内存中的8个字符作为打包的单精度浮点数加载到__m256变量中
- 内存,无理性和浮点数
- 将由空格分隔的浮点数组成的文本文件映射到浮点数向量的内存
- 类中的内存使用情况 - 将双精度转换为浮点数并未按预期减少内存使用量