在 64 位平台開發時是否應盡量避免使用指針?

你可能沒注意,64 位環境下,你能利用的總空間也變多了。

我更關心「效率怎麼定義」,如果你把它定義成一個百分比,那麼無論優不優化,都比 32 位的情況高。


xkcd 1691: Optimization

Premature optimization is the root of all evil, so to start this project Id better come up with a system that can determine whether a possible optimization is premature or not.


指針有時候避免不了,但是 size_t 這種東西,真的可以考慮一下,比如最簡單的:

struct string_t
{
char *ptr;
size_t capacity;
size_t size;
};

64位下:這個結構體 24位元組,如果把 size_t 換成 int 那麼變成 16位元組,節省了8位元組。

樓上樓下都在說內存不值錢,空間換性能,我提醒兩點:

  1. 大批量處理時的內存帶寬,你就拷貝個結構體,memcpy也是要耗時間的,不是 O(0)
  2. 緩存命中,更緊湊的結構體能將更多的數據放在 L1, L2 cache 中,提高處理速度。

你程序從 32位上升到了 64位,寄存器位寬是翻倍了,數量也多了,但是cpu運算能力並沒有翻倍,內存帶寬也並沒有翻倍。

假設你一個數組裡成千上萬個 string_t 結構體,需要進行密集的關聯運算,假設 L2 是256KB,用 size_t,你只能把 10922 個結構體放入 L2 中,而換成 int 後,你可以放 16384 個。再者,你在拷貝結構體數組時的代價也會更小。

就以 string_t 為例,size_t 換成 int ,你節省下來了 8位元組,你還可以把它用作8位元組的 SSO。

當然,上面說的前提是你已經優化到這一步了,需要進行緩存/內存優化了。


我沒搞過工程也不是 CS 專業的,這裡只是一些猜測:

如果開發中用 32 位地址值取代 64 位指針,那麼首先需要劃定一或多塊空間(靜態或動態),以在其中用 32 位值定址。這些空間每個都要有自己的 malloc/free (或者說 operator new/operator delete ),返回或接受一個 32 位偽指針。

這樣才能把使用指針的演算法挪到這種「子系統」上。但這種編碼難度仍然比原先的高不少,至少 C 中處理類型會相當麻煩。

(或者可以直接考慮用某個答案提及的 x32 ABI )

另外我看到有的題解里用 new node (而無 delete ),這裡也有多耗空間的問題,因為每個動態分配的內存塊都帶控制塊。

如果可以的話,開全局大數組,從裡面分配結點就行。(分配就 p = alloc_ptr++ 一句,一次性回收時重置 alloc_ptr = node_pool )。


要是真這麼在意…

雙向鏈表用xor大法

單向鏈表用高十六位搞事

連續內存塊用BitMap

犧牲時間換空間唄…

寫了一個內核消息隊列的內存池,就是大量使用xor和bitmap

於是性能很差勁…重寫了


這是個好問題。我用我淺薄的X86知識回答一下,可能有謬誤。

雖然在X86-64下,指針都是64位,但很少會有超過4GB以上的相對跳轉,所以X86-64在處理不超過4G的立即數、數組訪問和指令跳轉時,絕大多數都是用的4位元組的操作數。這樣做的好處是可以縮短指令長度。

int64_t* a=new int64_t[10240];
000000013F9A450A B9 00 40 01 00 mov ecx,14000h
000000013F9A450F E8 9E CD FF FF call operator new[] (013F9A12B2h)
000000013F9A4514 48 89 85 58 01 00 00 mov qword ptr [rbp+158h],rax
000000013F9A451B 48 8B 85 58 01 00 00 mov rax,qword ptr [rbp+158h]
000000013F9A4522 48 89 45 08 mov qword ptr [a],rax
int64_t* b = a + 1060;
000000013F9A4526 48 8B 45 08 mov rax,qword ptr [a]
000000013F9A452A 48 05 20 21 00 00 add rax,2120h
000000013F9A4530 48 89 45 28 mov qword ptr [b],rax
*b=10;
000000013F9A4534 48 8B 45 28 mov rax,qword ptr [b]
000000013F9A4538 48 C7 00 0A 00 00 00 mov qword ptr [rax],0Ah

看到機器碼里的立即數了嗎?都是32位的。包括調用new[]這個函數時,跳轉地址都是32位的相對地址。

因為堆棧都是64位的,所以傳遞參數時,用int32_t替代int64_t是不可能省內存的。


你們這些搞C++的,用個指針都覺得虧

8個位元組又不能到別人家裡看一圈


題主用 JavaScript、Python 做過開發,懂得高級語言的內存利用效率是很低的

???


首先,只有在用不到4G內存,還要求連續內存(數組)的結構上才能用這種下標(算是一種scoped pointer)省空間,鏈表或其他場景就不行了。這裡就有個統一性問題,我同時引用數組和鏈表的元素就又得滾回primitive pointer,使得這個方案應用場景較為狹隘。

其次,在一些情況下這裡確實是個可以省空間的地方,但同時有時間、編碼、維護複雜度開銷,增加了出bug的幾率,在實現需求的情況下當然是越簡單越好。再者有時用指針就是為了訪問快速/便利,那再壓空間就得不償失了。如果你確實被需求卡空間了,那再做這個優化也不遲。

題主似乎對「一般不需要考慮」這個答案不太滿意,實際上很多情況下時空複雜度甚至都不是瓶頸,編碼複雜度才是,不然Python這麼慢又大占空間怎麼會這麼流行。或者說,在弄清楚瓶頸到底在哪裡之前,做這種不是零開銷(減少某些開銷,增加另一些開銷)的「優化」,萬一搞不好就變成劣化了。

「過早的優化是萬惡之源」這種說法對不對,為什麼?www.zhihu.com圖標

如果所有代碼都是你自己的,需求也確定了,那用什麼你隨意。


否。

與指針大小膨脹相對應的是內存大小膨脹。

你不得不考慮如果單個進程佔用內存較大時不使用指針索引內存困難的問題。


我們只討論高性能運算的情況, 別的領域真的不差那點資源. (軟硬環境更新周期太快, 你上周寫的代碼, 下周可能需求就改了, 所以可用比優化重要)

高性能運算通常吃海量內存, 所以90%的情況, 64位地址是救世之光. 你明明想要循環運算1個T的數據, 那就不要想那麼多了. 在少數情況下, 我們需要一些精巧的小表格(其實幾個G對高性能運算絕對算精巧的了), 這個就是Donald Knuth在抱怨的問題. 這個問題可以用x32ABI解決(我沒事試過), 也可以用tagged pointer, 區別就是abi是面向編譯模塊的, tagged是線程內的, 看你的需求了.

總感覺我們的演算法競賽都是準備培養單片機人才的, 對資源佔用超在意. 題主如果以後不準備為國效力開發洲際導彈什麼的, 請務必放棄這種思維方式.


你這是學院派思想,不是工程派思想。

你自己都說了,如何從時間佔用、空間佔用、編程複雜度等多方面考慮這個問題?

那就從時間佔用、空間佔用、編程複雜度考慮啊。

空想沒有用,你得實際動手才知道你需要的是什麼。

我覺得吧,你如果能做連指針空間都需要優化的程序,那估計你也不會來提問了...


在 16 位平台開發時是否應盡量避免使用指針?

8 位平台中,指針類型佔用 1 個位元組,而在 16 位操作系統中,指針類型佔用 2 個位元組,是 8 位平台上的兩倍。在實現數據結構時,指針佔用的兩倍空間對程序內存佔用量的影響尤為明顯。

而一些情況下,指針是可以用數組的下標引用來代替的(靜態 / 動態分配一個數組),這時引用對象的內存佔用可能縮小到 1 個位元組(如果數據範圍長度在 8 位內)或更小,但會使代碼更複雜、不夠清晰。在這種情況下,我們是否應該避免使用指針類型?

如何從時間佔用、空間佔用、編程複雜度等多方面考慮這個問題?

在 32 位平台開發時是否應盡量避免使用指針?

16 位平台中,指針類型佔用 2 個位元組,而在 32 位操作系統中,指針類型佔用 4 個位元組,是 16 位平台上的兩倍。在實現數據結構時,指針佔用的兩倍空間對程序內存佔用量的影響尤為明顯。

而一些情況下,指針是可以用數組的下標引用來代替的(靜態 / 動態分配一個數組),這時引用對象的內存佔用可能縮小到 2 個位元組(如果數據範圍長度在 16 位內)或更小,但會使代碼更複雜、不夠清晰。在這種情況下,我們是否應該避免使用指針類型?

如何從時間佔用、空間佔用、編程複雜度等多方面考慮這個問題?

在 64 位平台開發時是否應盡量避免使用指針?

32 位平台中,指針類型佔用 4 個位元組,而在 64 位操作系統中,指針類型佔用 8 個位元組,是 32 位平台上的兩倍。在實現數據結構時,指針佔用的兩倍空間對程序內存佔用量的影響尤為明顯。

而一些情況下,指針是可以用數組的下標引用來代替的(靜態 / 動態分配一個數組),這時引用對象的內存佔用可能縮小到 4 個位元組(如果數據範圍長度在 32 位內)或更小,但會使代碼更複雜、不夠清晰。在這種情況下,我們是否應該避免使用指針類型?

如何從時間佔用、空間佔用、編程複雜度等多方面考慮這個問題?

在 128 位平台開發時是否應盡量避免使用指針?

64 位平台中,指針類型佔用 8 個位元組,而在 128 位操作系統中,指針類型佔用 16 個位元組,是 64 位平台上的兩倍。在實現數據結構時,指針佔用的兩倍空間對程序內存佔用量的影響尤為明顯。

而一些情況下,指針是可以用數組的下標引用來代替的(靜態 / 動態分配一個數組),這時引用對象的內存佔用可能縮小到 8 個位元組(如果數據範圍長度在 64 位內)或更小,但會使代碼更複雜、不夠清晰。在這種情況下,我們是否應該避免使用指針類型?

如何從時間佔用、空間佔用、編程複雜度等多方面考慮這個問題?


如果考慮【信息學競賽】,那麼顯然,應當根據題目內存要求來決擇,如果內存很緊迫,那麼使用內存佔用較少的方法。

如果考慮【軟體工程】,在多數情況下,應使用最簡明、優雅的實現方法。如果為了內存佔用而犧牲代碼的簡潔性,那麼可謂是本末倒置(在少數情況下除外,如內存密集型應用)。不然,需要 Runtime 或 Garbage Collector 的語言、解釋型語言,又有什麼存在的意義呢?這類語言中一個「引用」的佔用內存比一個 64 bit 指針還大。


C/C+初學者的常見毛病:你想的太多了。

你要是看64位指針不爽,你可以編譯成32位的目標程序。


的確現在有嫌 64 位指針太長的,只用一部分位表示地址,一部分位存儲值。

Tagged pointer - Wikipediaen.wikipedia.org


一般來說這點空間還成不了瓶頸,反過來各種壓縮空間的方式反而容易拖慢運算……如果真的成了瓶頸你再試試用32位的索引或者往指針高16位塞東西試試。

強行往指針高位塞了一個16位數的效果,一般來說可以這樣壓縮一下指針。

Ptr& 的定義:

下面是一堆運算符重載之類的……


分頁阅读: 1 2 3