日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ 内存对齐 及 引用是否真的节省内存的一点思考

發布時間:2024/7/5 c/c++ 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ 内存对齐 及 引用是否真的节省内存的一点思考 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1. 內存對齊
    • 2. 遞歸中的內存對齊
    • 3. C++引用的本質
    • 4. 致謝

1. 內存對齊

通過以下語句,獲取變量的占用內存打下:

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
  • 計算機從內存讀取數據是按塊讀取的,一般是4或者8的倍數一塊,一起讀取
  • CPU和內存IO的硬件限制導致沒辦法將一個數據類型分在兩個塊中讀取
  • 內存對齊,可以加快程序的運行速度,一般編譯器會在后臺進行內存對齊優化,但是也不能做到十分完美
  • 內存對齊的參數可以更改,#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

2. 遞歸中的內存對齊

我在做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
以上均為win1064位操作系統 環境


目前通過結果,可以看見,

  • 參數的增多,遞歸層數會減小
  • 遞歸中的棧也遵守內存對齊原則
  • int 型的 & 對遞歸深度沒有造成影響(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程序就不爆棧了,跟認知的規律是不符合的,還請大佬看看什么原因?

3. C++引用的本質

參考: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通過了。

4. 致謝

感謝焦/huaix提出去掉&可以解決問題,開啟了我對這個問題的思考
感謝Thin-k.調試,確認是stack-overflow的問題
感謝CSDN群里的朋友熱心討論和研究,還有論壇朋友akari10032的解答
感謝hitskyer和阿福的答疑
感謝所有在網絡上分享知識的每一個博主!

參考鏈接:
帶你深入理解內存對齊最底層原理
C/C++內存對齊詳解

總結

以上是生活随笔為你收集整理的C++ 内存对齐 及 引用是否真的节省内存的一点思考的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。