在 64 位平台開發時是否應盡量避免使用指針?
怎麼可能
我Malt都是指針滿天飛的/逃認真答:
兩大忌諱:不要提前優化,不要過度優化不要提前優化就是指
你的程序遇到性能瓶頸之前放心寫,遇到了再說不要過度優化是指
優化過程中那麼一丁點性能都要摳,這是不對的你有些時候手動優化出來的反而還沒編譯器幫你優化的好,而且可能破壞原本邏輯,降低代碼可讀性(可維護性)等我以前寫個人項目的時候沒經驗,被坑的很慘啊我的回答是:
是否應該避免使用指針,應該取決於你具體的業務場景,畢竟在當前的體系下,一個ptr也就是一個字長而已。
但是我想說的是,在生產環境:
- 指針的解引用是有開銷的。(PS:不同語言會有差異)
- 如果是有GC的語言,對垃圾回收也不友好。
我給你一個實際生產環境的例子:
golang loop benchmark
執行命令為:go test -v -bench=. normal_loop_test.go -benchmemenv:go version go1.9.2 darwin/amd64
結果如圖:
因此,如果你的QPS很高,常數非常大,在效率上和緩存的友好度上,當然是非指針更好啦。
你處理器的位寬是64位的,你讀「一個」32位數據和「一個」64為數據所需的時間「絕大多數情況下」是一樣的
當然有些短於8位元組的struct改用值傳遞可以更好一些……但是你至於到這麼斤斤計較的地步么指針該用就用,不要濫用就行,一般不會有明顯的空間與時間的佔用提升。
況且64位cpu可用的寄存器多,普遍速度也夠快。
濫用:比如多維數組用指針套指針的方式存就是濫用。
一派胡言 你算一算都知道是否可行了 這麼說吧 別說什麼工程代碼了 你寫個最簡單的bug free的demo出來 再來討論「talk is cheap, show me the * code」另吐個槽 沒拿個金牌什麼的那就是搞過競賽而已 演算法競賽出身這種話還是別說了
1,在CPU定址的時候不一定是絕對定址。2,現在的CPU都有分頁分段功能,在同一段地址下地址的長度會比64位少。3,若為短定址指令等等,需要的地址位元組就更少了,不一定會佔用更多的內存空間。4,需要用到長跳轉指令的情況非常少,一般是先指定段基地址,然後指定偏移量,經過段映射,頁映射等等多級映射才對應至cache。5,編譯器在編譯的時候優先分配連續內存空間(邏輯地址),因為相對定址比絕對定址要快,指令長度更短。而相對定址對應的指令32位與64位相差不大(x86架構屬於CISC,指令不等長)。6,64位不僅僅意味著地址為64位,數據也為64位,在計算64位定點數或80位浮點數的情形下,64位CPU計算能力更強。7,結論:不會影響性能(運行速度,佔用的內存空間),甚至會提升性能。8,本回答純爪機打字,邏輯不清晰,可能有錯誤,望大神輕拍。
程序的位元組對齊 也很重要啊 如果機器內部一次傳輸8位元組的數據 那4位元組的數據是很尷尬的吧
可是64位cpu寄存器也變大了啊
你乾脆也別用數組了,地址也是64位,也不要用函數了,統統64位。
按照這個邏輯,智能指針豈不是更要淘汰了
這個問題很簡單,空間換時間 還是 時間換空間?
在 64 位系統上用 4 個位元組(或者更少)存儲指針是一種時間換空間的策略。因為每一次使用指針都需要做額外的計算來獲取指針的 64 位地址。
那麼很明顯,如果程序的瓶頸在 CPU 上,這樣做是不合適的。而如果程序的瓶頸在內存上,這樣做是一種可以考慮的選擇。
事實上,在 x86-64 上,指針的高 16 位(以及低 2 位)都是不會使用的。如果你想的話,都可以用來存儲數據。也確實有人是這麼做的 -&> RAPIDJSON_48BITPOINTER_OPTIMIZATION
所以,如何選擇取決於實際需要,並沒有一定是或者不是的答案。
我說一下我的第一反應,因為cs專業課是學渣,可能學的混了說不對,希望大家糾正。
從cpu組成原理來考慮,64位系統一個字長64bit,這是數據的最小基本單位,包括cpu各個寄存器的長度也都是64或者64的倍數,內存和cpu之間一個讀或者取周期用過的也是64bit。
如果使用和字長相等的數據類型,那麼一切按部就班沒有什麼可說的。
如果數據類型小於字長,那麼需要「取一個完整的字並只操作其中的一部分」,例如使用32位int,本質上是一個64長度的字的高32位或者低32位,相比直接操作64位數據,需要更多的乘法、移位等操作來實現「只操作其中的一部分」,這樣反而會導致運行引入更多的時間複雜度,原來一個cpu周期的操作可能變得需要n多個周期。
另外還有一個內存對齊機制,以保證那些能夠應當能被訪問到的內容能通過指針直接訪問,對於int32數組想省空間沒有問題,但對於多個單獨存在的int32,或者多種數據類型組成的struct,就需要在一個字內對齊,放棄剩餘的字內空間,就可能會導致期望的「省內存」效果無法達成。
以及會有在應用開發中,為了用32位被迫修改自己演算法的額外開發成本和debug成本,在開發成本較高、內存操作玩的6的人很少的今天,隨便一個程序員一個月工資就不知道能買多少內存,所以應用開發中,一般認為是虧的。
儘管我沒有演算法經歷吧,我個人覺得演算法競賽應該更多追求在演算法邏輯上的最優,而不是給台64bit機器配512M內存跑數據,這個有點過了。而一些情況下,指針是可以用數組的下標引用來代替的(靜態 / 動態分配一個數組),這時引用對象的內存佔用可能縮小到 4 個位元組(如果數據範圍長度在 32 位內)或更小,但會使代碼更複雜、不夠清晰。
有答主提出不需要考慮這些,那麼,應用程序開發對效率的要求比演算法競賽低嗎?
題主也說了,會使代碼更複雜、不夠清晰,那麼很顯然,把指針換成索引會導致開發效率降低;同時額外的"索引-指針"查詢轉換工作會降低運行效率(考慮到多線程下,這個索引與指針的查詢和轉換還需要加鎖進行線程同步,性能損失會更大),對大部分應用程序來說,這裡損失的運行效率遠超過節省4位元組內存帶來的提升,畢竟大部分64位程序不怎麼缺內存,指針也不會是程序佔用內存最多的數據類型,所以即使每個指針佔用了2倍的內存,整個程序的內存佔用也是遠低於2倍的。
所以,如果一個技術同時降低了開發效率和運行效率,對於對內存佔用不那麼敏感並且對開發效率要求更高的應用程序開發,為什麼要使用它呢?
以前學習AVL樹,測試的時候生成大量數據去插入、遍歷、刪除,涉及了大量頻繁的指針操作,同樣的機器編譯為64位的程序確實比32位的耗時多了不少。但是不用指針用什麼呢?
首先膜一發 Menci(逃
要知道,數組的下標訪問只是一個語法糖,在彙編層面與指針訪問沒有任何差別。
而對於預先分配對象數組這件事情,可以說是完全拋棄了 C++ 的多態性,完全無法組織具有公共父類的一組派生對象;使用指針則沒有這個問題。
真嫌64位指針佔用空間大,那就:
TYPE i;
uint32_t pointer_32 = (uint32_t)i;
用的時候再:
*(TYPE *)pointer_32 = blabla;
不過這樣做顯然是沒有任何意義的,為啥不 target x86 呢?
推薦閱讀:
※C++中為什麼派生類中只有基本類型時,delete一個指向派生類的基類指針時卻沒有內存泄漏?
※c++在執行運行時多態時,為什麼需要借用rtti來判斷對象真實類型?
※一個關於C++模板的問題?
※關於c++模板推導失敗,這是編譯器的bug嗎?
※《深度探索c++對象模型》,C語言有沒有類似的書,講解C語言低層細節及編譯器所做工作?