通过以下语句,获取变量的占用内存打下:
cout << "size of int " << sizeof(int) << endl;
cout << "size of int& " << sizeof(int&) << endl;
cout << "size of char " << sizeof(char) << endl;
int 和 int& 都占 4 字节, char 占 1 字节
编写一个类:其包含1个 int,2个 char,排列顺序不同。
class memory1
{
int id;
char a;
char b;
};
class memory2
{
char a;
int id;
char b;
};
class memory3
{
char a;
char b;
int id;
};
可以看见,他们的占用空间大小是不一样的。
size of memory1 8
size of memory2 12
size of memory3 8
#pragma pack(n),n = 1,2,4,8,16
所以上面的memory类的内存对齐是按照4字节进行的,计算机按照顺序分配内存,4字节剩余空间能放下某个类型的,就放进去,放不进去的,新往下找一块4字节的空间放 int
加入#pragma pack(1)
,可见就是紧密排列了。
size of memory1 6
size of memory2 6
size of memory3 6
#pragma pack(2)
size of memory1 6
size of memory2 8
size of memory3 6
我在做LeetCode题的时候遇到一个递归爆栈问题:
在这里做一些测试,不保证结果具有通用性,也请大家指正。
void dfs(int i) {
int k = 0;
cout << "&k = " << &k << endl;
cout << "i = " << i << endl;
i = i+1;
dfs(i);
}
int main() {
int i = 0;
dfs(i);
}
变更dfs(i)
参数个数
递归次数:32385,第一个k的地址 0x61fdcc
,k地址间隔 6410(参数个数为1-4个)
增加参数个数到(5-6个):
递归次数:25908,第一个k的地址 0x61fdbc
(比上面移动了16),k地址间隔 8010
增加参数个数到(7-8个):
递归次数:21589,第一个k的地址 0x61fdac
(比上面移动了32),k地址间隔 9610
增加参数个数到(9-10个):
递归次数:18505,第一个k的地址 0x61fd8c
(比上面移动了64),k地址间隔 11210
增加参数个数到(11个):
递归次数:16191,第一个k的地址 0x61fd7c
(比上面移动了80),k地址间隔 12810
增加参数个数到(10个,且全部改成&
引用):
递归次数:18505,第一个k的地址 0x61fd8c
(比上面移动了64),k地址间隔 11210
以上均为win10
64位操作系统 环境
目前通过结果,可以看见,
&
对递归深度没有造成影响(win10,64位)class memory1
{
int id;
char a[1280];
char b;
};
int main() {
int i = 0;
int j = 0;
int a = 0, b = 0, c = 0,d=0,e=0,f=0,g=0,h=0,l=0;
memory1 m1;
dfs(m1,i, j, a, b,c,d,e,f,g,h);
}
size of memory1 1288
上面程序,
递归次数:1436,第一个k的地址 0x61f34c
(比上面移动了2688),k地址间隔 144010
将 m1 改成&
:
cout << "size of memory1& " << sizeof(&m1) << endl;
size of memory1& 8
递归次数:16181,第一个k的地址 0x61f86c
(比上面移动了1376),k地址间隔 12810
&
能大幅节省空间,递归不至于过早爆栈结束。但是,上面 LeetCode 爆栈就只是把 int&
改成int
程序就不爆栈了,跟认知的规律是不符合的,还请大佬看看什么原因?
参考:c++中“引用”的底层实现原理详解 在读完上文后,就清楚了,引用会产生一个8字节的变量存储被引用的变量的地址,所以上面win10的测试结果,有点不可信,可能这就是C++在硬件、操作系统、编译器不同的情况下结果有差异的情况,采用 linux 进行测试
在linux中测试结果:
传入2个int
: 递归次数174522
传入2个int&
:递归次数130885
传入2个double
: 递归次数130912
传入2个double&
:递归次数104668
我想这个数值,已经能够侧面说明上面链接文章中提到的引用本质了,C++引用的本质是指针,但是它跟指针又不一样,C++对指针进行了封装产生了引用,你在使用引用的时候,传给你的是它里面指针所指向的内容。
所以对这种内置的变量类型,函数调用的时候,直接使用copy传入就可以了,还比较省内存(int 4字节,使用 int & 会占用 8字节)
至此,可以解释上面 LeetCode 那道题,传入 int & 爆栈了,而改为 int ,题目就AC通过了。
感谢焦/huaix
提出去掉&
可以解决问题,开启了我对这个问题的思考
感谢Thin-k.
调试,确认是stack-overflow
的问题
感谢CSDN
群里的朋友热心讨论和研究,还有论坛朋友akari10032
的解答
感谢hitskyer
和阿福
的答疑
感谢所有在网络上分享知识的每一个博主!
参考链接: 带你深入理解内存对齐最底层原理 C/C++内存对齐详解