搬運(yùn)自牛客網(wǎng)大神總結(jié)
extern關(guān)鍵字
- extern修飾變量
是個(gè)聲明,此變量/函數(shù)是在別處定義的,要在此處引用 - extern修飾函數(shù)
暗示這個(gè)函數(shù)可能在別的源文件里定義,沒(méi)有其它作用碍论。 - extern C的作用?用法荐吵?
告訴編譯器在編譯函數(shù)名時(shí)按著C的規(guī)則去翻譯相應(yīng)的函數(shù)名而不是C++的(C++要支持多態(tài)骑冗,C沒(méi)有)
static關(guān)鍵字作用
- 修飾局部變量
被修飾的變量成為靜態(tài)變量,存儲(chǔ)在靜態(tài)區(qū)先煎。存儲(chǔ)在靜態(tài)區(qū)的數(shù)據(jù)生命周期與程序相同贼涩,在main函數(shù)之前初始化,在程序退出時(shí)銷(xiāo)毀薯蝎。(無(wú)論是局部靜態(tài)還是全局靜態(tài))
局部靜態(tài)變量使得該變量在退出函數(shù)后遥倦,不會(huì)被銷(xiāo)毀,因此再次調(diào)用該函數(shù)時(shí),該變量的值與上次退出函數(shù)時(shí)值相同袒哥。值得注意的是缩筛,生命周期并不代表其可以一直被訪問(wèn),因?yàn)樽兞康脑L問(wèn)還受到其作用域的限制堡称。 - 修飾全局變量
全局變量本來(lái)就存儲(chǔ)在靜態(tài)區(qū)瞎抛,因此static并不能改變其存儲(chǔ)位置。但是却紧,static限制了其鏈接屬性桐臊。被static修飾的全局變量只能被該包含該定義的文件訪問(wèn)。 - static修飾函數(shù)使得函數(shù)只能在包含該函數(shù)定義的文件中被調(diào)用晓殊。
- static修飾成員變量
static修飾的變量先于對(duì)象存在断凶,所以static修飾的變量要在類(lèi)外初始化。因?yàn)閟tatic是所有對(duì)象共享的東西嘛巫俺,必須要比對(duì)象先存在的认烁。
static在C++中對(duì)于靜態(tài)成員變量和靜態(tài)成員函數(shù)。所有的對(duì)象都只維持同一個(gè)實(shí)例介汹。相當(dāng)于類(lèi)的屬性
- static修飾成員函數(shù)
- 由于static修飾的類(lèi)成員屬于類(lèi)却嗡,不屬于對(duì)象,因此static類(lèi)成員函數(shù)是沒(méi)有this指針的痴昧,this指針是指向本對(duì)象的指針稽穆。正因?yàn)闆](méi)有this指針冠王,所以static類(lèi)成員函數(shù)不能訪問(wèn)非static的類(lèi)成員赶撰,只能訪問(wèn) static修飾的類(lèi)成員。
- 注意事項(xiàng)
- 出現(xiàn)在類(lèi)體外的函數(shù)不能指定關(guān)鍵字static柱彻;
- 靜態(tài)成員之間可以互相訪問(wèn)豪娜,包括靜態(tài)成員函數(shù)訪問(wèn)靜態(tài)數(shù)據(jù)成員和訪問(wèn)靜態(tài)成員函數(shù);
- 非靜態(tài)成員函數(shù)可以任意地訪問(wèn)靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員哟楷;
- 靜態(tài)成員函數(shù)不能訪問(wèn)非靜態(tài)成員函數(shù)和非靜態(tài)數(shù)據(jù)成員瘤载;
- 由于沒(méi)有this指針的額外開(kāi)銷(xiāo),因此靜態(tài)成員函數(shù)與類(lèi)的全局函數(shù)相比卖擅,速度上會(huì)有少許的增長(zhǎng)鸣奔;
- 調(diào)用靜態(tài)成員函數(shù),可以用成員訪問(wèn)操作符(.)和(->)為一個(gè)類(lèi)的對(duì)象或指向類(lèi)對(duì)象的指調(diào)用靜態(tài)成員函數(shù)惩阶。
volatile關(guān)鍵字
- 訪問(wèn)寄存器要比訪問(wèn)內(nèi)存要塊挎狸,因此CPU會(huì)優(yōu)先訪問(wèn)該數(shù)據(jù)在寄存器中的存儲(chǔ)結(jié)果,但是內(nèi)存中的數(shù)據(jù)可能已經(jīng)發(fā)生了改變断楷,而寄存器中還保留著原來(lái)的結(jié)果锨匆。為了避免這種情況的發(fā)生將該變量聲明為volatile,告訴CPU每次都從內(nèi)存去讀取數(shù)據(jù)冬筒。
- 一個(gè)參數(shù)可以即是const又是volatile的嗎恐锣?可以茅主,一個(gè)例子是只讀狀態(tài)寄存器,是volatile是因?yàn)樗赡鼙灰庀氩坏降谋桓淖兺亮瘢莄onst告訴程序不應(yīng)該試圖去修改他诀姚。
enum枚舉變量
某個(gè)枚舉變量的值默認(rèn)為前一個(gè)變量值加一
第一個(gè)枚舉變量默認(rèn)值為0
枚舉變量值是可以重復(fù)的
const的作用
修飾變量,局部變量玷禽,全局變量学搜,成員變量(必須初始值列表)
修飾引用作為函數(shù)參數(shù),保護(hù)值不會(huì)改變论衍,同時(shí)也針對(duì)常量參數(shù)
修飾成員函數(shù)瑞佩,類(lèi)的成員函數(shù)加上const限定可以聲明此函數(shù)不會(huì)更改類(lèi)對(duì)象的內(nèi)容(并不牢靠)
修飾返回值,表明返回的數(shù)據(jù)是不可修改的
修飾指針坯台,左定值炬丸,右定向,const在*左側(cè)表示所指內(nèi)容是常量蜒蕾,在*右側(cè)表示指針本身是常量不可變
new和malloc區(qū)別
- new分配內(nèi)存按照數(shù)據(jù)類(lèi)型進(jìn)行分配稠炬,malloc分配內(nèi)存按照大小分配;
- new不僅分配一段內(nèi)存咪啡,而且會(huì)調(diào)用構(gòu)造函數(shù)首启,但是malloc則不會(huì)。new的實(shí)現(xiàn)原理撤摸?但是還需要注意的是毅桃,之前看到過(guò)一個(gè)題說(shuō)int p = new int與int p = new int()的區(qū)別,因?yàn)閕nt屬于C++內(nèi)置對(duì)象准夷,不會(huì)默認(rèn)初始化钥飞,必須顯示調(diào)用默認(rèn)構(gòu)造函數(shù),但是對(duì)于自定義對(duì)象都會(huì)默認(rèn)調(diào)用構(gòu)造函數(shù)初始化衫嵌。翻閱資料后读宙,在C++11中兩者沒(méi)有區(qū)別了,自己測(cè)試的結(jié)構(gòu)也都是為0楔绞;
- new返回的是指定對(duì)象的指針结闸,而malloc返回的是void*,因此malloc的返回值一般都需要進(jìn)行類(lèi)型轉(zhuǎn)化酒朵;
- new是一個(gè)操作符可以重載桦锄,malloc是一個(gè)庫(kù)函數(shù);
- new分配的內(nèi)存要用delete銷(xiāo)毀耻讽,malloc要用free來(lái)銷(xiāo)毀察纯;delete銷(xiāo)毀的時(shí)候會(huì)調(diào)用對(duì)象的析構(gòu)函數(shù),而free則不會(huì);
- malloc分配的內(nèi)存不夠的時(shí)候饼记,可以用realloc擴(kuò)容香伴。擴(kuò)容的原理?new沒(méi)用這樣操作具则;
- new如果分配失敗了會(huì)拋出bad_malloc的異常即纲,而malloc失敗了會(huì)返回NULL。因此對(duì)于new博肋,正確的姿勢(shì)是采用try...catch語(yǔ)法低斋,而malloc則應(yīng)該判斷指針的返回值。為了兼容很多c程序員的習(xí)慣,C++也可以采用new nothrow的方法禁止拋出異常而返回NULL;
- new和new[]的區(qū)別翘盖,new[]一次分配所有內(nèi)存迫卢,多次調(diào)用構(gòu)造函數(shù)律歼,分別搭配使用delete和delete[],同理,delete[]多次調(diào)用析構(gòu)函數(shù),銷(xiāo)毀數(shù)組中的每個(gè)對(duì)象买猖。而malloc則只能sizeof(int) * n;
- 如果不夠可以繼續(xù)談new和malloc的實(shí)現(xiàn)滋尉,空閑鏈表玉控,分配方法(首次適配原則,最佳適配原則狮惜,最差適配原則高诺,快速適配原則)。delete和free的實(shí)現(xiàn)原理讽挟,free為什么直到銷(xiāo)毀多大的空間懒叛?
C++多態(tài)性與虛函數(shù)
- C++多態(tài)的實(shí)現(xiàn)
多態(tài)分為靜態(tài)多態(tài)和動(dòng)態(tài)多態(tài)。靜態(tài)多態(tài)是通過(guò)重載和模板技術(shù)實(shí)現(xiàn)耽梅,在編譯的時(shí)候確定。動(dòng)態(tài)多態(tài)通過(guò)虛函數(shù)和繼承關(guān)系來(lái)實(shí)現(xiàn)胖烛,執(zhí)行動(dòng)態(tài)綁定眼姐,在運(yùn)行的時(shí)候確定。
動(dòng)態(tài)多態(tài)實(shí)現(xiàn)有幾個(gè)條件:
(1) 虛函數(shù)佩番;
(2) 一個(gè)基類(lèi)的指針或引用指向派生類(lèi)的對(duì)象众旗;
基類(lèi)指針在調(diào)用成員函數(shù)(虛函數(shù))時(shí),就會(huì)去查找該對(duì)象的虛函數(shù)表趟畏。虛函數(shù)表的地址在每個(gè)對(duì)象的首地址贡歧。查找該虛函數(shù)表中該函數(shù)的指針進(jìn)行調(diào)用。
每個(gè)對(duì)象中保存的只是一個(gè)虛函數(shù)表的指針,C++內(nèi)部為每一個(gè)類(lèi)維持一個(gè)虛函數(shù)表利朵,該類(lèi)的對(duì)象的都指向這同一個(gè)虛函數(shù)表律想。
虛函數(shù)表中為什么就能準(zhǔn)確查找相應(yīng)的函數(shù)指針呢?因?yàn)樵陬?lèi)設(shè)計(jì)的時(shí)候绍弟,虛函數(shù)表直接從基類(lèi)也繼承過(guò)來(lái)技即,如果覆蓋了其中的某個(gè)虛函數(shù),那么虛函數(shù)表的指針就會(huì)被替換樟遣,因此可以根據(jù)指針準(zhǔn)確找到該調(diào)用哪個(gè)函數(shù)而叼。 - 虛函數(shù)的作用
- 用于實(shí)現(xiàn)多態(tài)
- 在設(shè)計(jì)上還具有封裝和抽象的作用。比如抽象工廠模式豹悬。
- 動(dòng)態(tài)綁定是如何實(shí)現(xiàn)的
- 靜態(tài)多態(tài)和動(dòng)態(tài)多態(tài)
靜態(tài)多態(tài)是指通過(guò)模板技術(shù)或者函數(shù)重載技術(shù)實(shí)現(xiàn)的多態(tài)葵陵,其在編譯器確定行為。動(dòng)態(tài)多態(tài)是指通過(guò)虛函數(shù)技術(shù)實(shí)現(xiàn)在運(yùn)行期動(dòng)態(tài)綁定的技術(shù)瞻佛。 -
虛函數(shù)表
編譯器為每一個(gè)類(lèi)維護(hù)一個(gè)虛函數(shù)表埃难,每個(gè)對(duì)象的首地址保存著該虛函數(shù)表的指針,同一個(gè)類(lèi)的不同對(duì)象實(shí)際上指向同一張?zhí)摵瘮?shù)表涤久。 - 純虛函數(shù)
純虛函數(shù)定義 virtual ~myClass() = 0; - 為什么對(duì)于存在虛函數(shù)的類(lèi)中析構(gòu)函數(shù)要定義成虛函數(shù)
為了實(shí)現(xiàn)多態(tài)進(jìn)行動(dòng)態(tài)綁定涡尘,將派生類(lèi)對(duì)象指針綁定到基類(lèi)指針上,對(duì)象銷(xiāo)毀時(shí)响迂,如果析構(gòu)函數(shù)沒(méi)有定義為析構(gòu)函數(shù)考抄,則會(huì)調(diào)用基類(lèi)的析構(gòu)函數(shù),顯然只能銷(xiāo)毀部分?jǐn)?shù)據(jù)蔗彤。如果要調(diào)用對(duì)象的析構(gòu)函數(shù)川梅,就需要將該對(duì)象的析構(gòu)函數(shù)定義為虛函數(shù),銷(xiāo)毀時(shí)通過(guò)虛函數(shù)表找到對(duì)應(yīng)的析構(gòu)函數(shù)然遏。 - 析構(gòu)函數(shù)能拋出異常嗎贫途?
肯定是不能。 C++標(biāo)準(zhǔn)指明析構(gòu)函數(shù)不能待侵、也不應(yīng)該拋出異常丢早。C++異常處理模型最大的特點(diǎn)和優(yōu)勢(shì)就是對(duì)C++中的面向?qū)ο筇峁┝俗顝?qiáng)大的無(wú)縫支持。那么如果對(duì)象在運(yùn)行期間出現(xiàn)了異常秧倾,C++異常處理模型有責(zé)任清除那些由于出現(xiàn)異常所導(dǎo)致的已經(jīng)失效了的對(duì)象(也即對(duì)象超出了它原來(lái)的作用域)怨酝,并釋放對(duì)象原來(lái)所分配的資源, 這就是調(diào)用這些對(duì)象的析構(gòu)函數(shù)來(lái)完成釋放資源的任務(wù)那先,所以從這個(gè)意義上說(shuō)农猬,析構(gòu)函數(shù)已經(jīng)變成了異常處理的一部分。
- 如果析構(gòu)函數(shù)拋出異常售淡,則異常點(diǎn)之后的程序不會(huì)執(zhí)行斤葱,如果析構(gòu)函數(shù)在異常點(diǎn)之后執(zhí)行了某些必要的動(dòng)作比如釋放某些資源慷垮,則這些動(dòng)作不會(huì)執(zhí)行,會(huì)造成諸如資源泄漏的問(wèn)題揍堕。
- 通常異常發(fā)生時(shí)料身,c++的機(jī)制會(huì)調(diào)用已經(jīng)構(gòu)造對(duì)象的析構(gòu)函數(shù)來(lái)釋放資源,此時(shí)若析構(gòu)函數(shù)本身也拋出異常鹤啡,則前一個(gè)異常尚未處理惯驼,又有新的異常,會(huì)造成程序崩潰的問(wèn)題递瑰。
- 構(gòu)造函數(shù)可以調(diào)用虛函數(shù)嗎祟牲?
不可以,構(gòu)造是按繼承順序的抖部,先基類(lèi)说贝,后派生類(lèi),如果構(gòu)造期間調(diào)用了一個(gè)子類(lèi)的虛函數(shù)慎颗,但是子類(lèi)還未構(gòu)造出來(lái)乡恕,出現(xiàn)未定義行為。析構(gòu)函數(shù)同理俯萎。
C++空類(lèi)默認(rèn)的成員函數(shù)
C++中空類(lèi)默認(rèn)會(huì)產(chǎn)生以下6個(gè)函數(shù):
- 默認(rèn)構(gòu)造函數(shù)
- 復(fù)制構(gòu)造函數(shù)
- 析構(gòu)函數(shù)
- 賦值運(yùn)算符重載函數(shù)
- 取地址符重載函數(shù)
- const取地址符重載函數(shù)
指針和引用
- 指針保存的是所指對(duì)象的地址傲宜,引用是所指對(duì)象的別名,指針需要通過(guò)解引用間接訪問(wèn)夫啊,而引用是直接訪問(wèn)函卒;
- 指針可以改變地址,從而改變所指的對(duì)象撇眯,而引用必須從一而終报嵌;
- 引用在定義的時(shí)候必須初始化,而指針則不需要熊榛;
- 指針有指向常量的指針和指針常量锚国,而引用沒(méi)有常量引用;
- 指針更靈活玄坦,用的好威力無(wú)比血筑,用的不好處處是坑,而引用用起來(lái)則安全多了营搅,但是比較死板云挟。
指針與數(shù)組
- 一個(gè)一維int數(shù)組的數(shù)組名實(shí)際上是一個(gè)int* const 類(lèi)型;
- 一個(gè)二維int數(shù)組的數(shù)組名實(shí)際上是一個(gè)int (*const p)[n];
- 數(shù)組名做參數(shù)會(huì)退化為指針转质,除了sizeof
C++中異常的處理方法
關(guān)鍵字有try, catch, throw
使用try{} catch(){}來(lái)捕獲異常,如果本級(jí)沒(méi)有帶適當(dāng)類(lèi)型參數(shù)的catch塊帖世,則不能捕獲異常休蟹,異常就會(huì)向上一級(jí)傳遞沸枯,如果一直沒(méi)有捕獲,C++會(huì)使用默認(rèn)的異常處理函數(shù)
回調(diào)函數(shù)
回調(diào)函數(shù)是通過(guò)函數(shù)指針調(diào)用的函數(shù)赂弓,把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù)
回調(diào)函數(shù)與應(yīng)用程序接口(API)非常接近绑榴,都是跨層調(diào)用的函數(shù),區(qū)別是API是低層給高層的調(diào)用盈魁,回調(diào)函數(shù)則相反翔怎,是高層提供給低層的調(diào)用,必須由高層來(lái)安裝
內(nèi)存泄露
所謂內(nèi)存泄漏是指由于疏忽或錯(cuò)誤導(dǎo)致程序未能釋放已經(jīng)不再使用的內(nèi)存的情況杨耙,一般指堆內(nèi)存的泄露赤套,失去對(duì)該段內(nèi)存的控制,因而造成了內(nèi)存的浪費(fèi)珊膜,會(huì)導(dǎo)致CPU資源耗盡的嚴(yán)重后果
緩沖區(qū)溢出
緩沖區(qū)是成勛運(yùn)行的時(shí)候機(jī)器內(nèi)存的一個(gè)連續(xù)塊
當(dāng)向緩沖區(qū)內(nèi)填充數(shù)據(jù)位數(shù)超過(guò)了緩沖區(qū)自身的容量限制容握,發(fā)生溢出的數(shù)據(jù)覆蓋在合法數(shù)據(jù)(數(shù)據(jù),下一條指令的指針车柠,函數(shù)返回地址等)剔氏,解決辦法是檢查數(shù)據(jù)長(zhǎng)度
野指針與空懸指針
- 野指針是指向不可用內(nèi)存的指針,沒(méi)有被正確的初始化竹祷,指向隨機(jī)地址
- 空懸指針:曾經(jīng)指向有效地址谈跛,但原來(lái)內(nèi)存被釋放了,現(xiàn)在不再有效
椝芰辏空間的最大值
windows下棧的大小是2MB感憾,堆的大小一般小于2GB
Linux默認(rèn)棧空間大小為8MB猿妈,可以通過(guò) ulimit -s 來(lái)設(shè)置
智能指針的原理和實(shí)現(xiàn)
1. 構(gòu)造函數(shù)中計(jì)數(shù)初始化為1吹菱;
2. 拷貝構(gòu)造函數(shù)中計(jì)數(shù)值加1;
3. 賦值運(yùn)算符中彭则,左邊的對(duì)象引用計(jì)數(shù)減一鳍刷,右邊的對(duì)象引用計(jì)數(shù)加一;
4. 析構(gòu)函數(shù)中引用計(jì)數(shù)減一俯抖;
5. 在賦值運(yùn)算符和析構(gòu)函數(shù)中输瓜,如果減一后為0,則調(diào)用delete釋放對(duì)象芬萍。
6. share_prt<T>與weak_ptr<T>的區(qū)別尤揣?
share_ptr可能出現(xiàn)循環(huán)引用,從而導(dǎo)致內(nèi)存泄露
class A
{
public:
share_ptr<B> p;
};
class B
{
public:
share_ptr<A> p;
}
int main()
{
while(true)
{
share_prt<A> pa(new A()); //pa的引用計(jì)數(shù)初始化為1
share_prt<B> pb(new B()); //pb的引用計(jì)數(shù)初始化為1
pa->p = pb; //pb的引用計(jì)數(shù)變?yōu)?
pb->p = pa; //pa的引用計(jì)數(shù)變?yōu)?
}
//假設(shè)pa先離開(kāi)柬祠,引用計(jì)數(shù)減一變?yōu)?北戏,不為0因此不會(huì)調(diào)用class A的析構(gòu)函數(shù),因此其成員p也不會(huì)被析構(gòu)漫蛔,pb的引用計(jì)數(shù)仍然為2嗜愈;
//同理pb離開(kāi)的時(shí)候旧蛾,引用計(jì)數(shù)也不能減到0
return 0;
}
weak_ptr是一種弱引用指針,其存在不會(huì)影響引用計(jì)數(shù)蠕嫁,從而解決循環(huán)引用的問(wèn)題
C++的四種類(lèi)型轉(zhuǎn)換
- const_cast用于將const變量轉(zhuǎn)為非const
- static_cast用的最多锨天,對(duì)于各種隱式轉(zhuǎn)換,非const轉(zhuǎn)const剃毒,void*轉(zhuǎn)指針等, static_cast能用于多態(tài)想上轉(zhuǎn)化病袄,如果向下轉(zhuǎn)能成功但是不安全,結(jié)果未知赘阀;
- dynamic_cast用于動(dòng)態(tài)類(lèi)型轉(zhuǎn)換益缠。只能用于含有虛函數(shù)的類(lèi),用于類(lèi)層次間的向上和向下轉(zhuǎn)化纤壁。只能轉(zhuǎn)指針或引用左刽。向下轉(zhuǎn)化時(shí),如果是非法的對(duì)于指針?lè)祷豊ULL酌媒,對(duì)于引用拋異常欠痴。要深入了解內(nèi)部轉(zhuǎn)換的原理。
- reinterpret_cast幾乎什么都可以轉(zhuǎn)秒咨,比如將int轉(zhuǎn)指針喇辽,可能會(huì)出問(wèn)題,盡量少用雨席;
- 為什么不使用C的強(qiáng)制轉(zhuǎn)換菩咨?C的強(qiáng)制轉(zhuǎn)換表面上看起來(lái)功能強(qiáng)大什么都能轉(zhuǎn),但是轉(zhuǎn)化不夠明確陡厘,不能進(jìn)行錯(cuò)誤檢查抽米,容易出錯(cuò)。
內(nèi)存對(duì)齊原則
- 從0位置開(kāi)始存儲(chǔ)糙置;
- 變量存儲(chǔ)的起始位置是該變量大小的整數(shù)倍云茸;
- 結(jié)構(gòu)體總的大小是其最大元素的整數(shù)倍,不足的后面要補(bǔ)齊谤饭;
- 結(jié)構(gòu)體中包含結(jié)構(gòu)體标捺,從結(jié)構(gòu)體中最大元素的整數(shù)倍開(kāi)始存;
- 如果加入pragma pack(n) 揉抵,取n和變量自身大小較小的一個(gè)亡容。
超高頻問(wèn)題
struct Q{
char c;
int num1;
double num2;
};
上述代碼中sizeof(Q)為多少? 16
struct的對(duì)其系數(shù)和以下幾個(gè)關(guān)系有關(guān)
- 元素大小
- 元素順序
- pragma參數(shù)
對(duì)齊規(guī)則
- struct中成員在內(nèi)存中按順序排列冤今,在沒(méi)有#pargma pack(n)的情況下闺兢,各個(gè)成員的對(duì)齊系數(shù)為自己的長(zhǎng)度
- 在有#pargma pack(n)的情況下,各個(gè)成員的對(duì)齊系數(shù)為min(自己的長(zhǎng)度戏罢,n)
- struct整體的對(duì)齊系數(shù)為對(duì)齊系數(shù)中最大的
- 依次排列時(shí)要滿(mǎn)足地址對(duì)對(duì)齊系數(shù)取模為0
內(nèi)聯(lián)函數(shù)有什么優(yōu)點(diǎn)列敲?與宏定義的區(qū)別阱佛?
- 宏定義在預(yù)處理階段進(jìn)行替換
- 內(nèi)聯(lián)函數(shù)在編譯階段帖汞,在調(diào)用內(nèi)聯(lián)函數(shù)的地方進(jìn)行替換戴而,減少了函數(shù)的調(diào)用過(guò)程,但是使得編譯文件變大翩蘸。因此所意,內(nèi)聯(lián)函數(shù)適合簡(jiǎn)單函數(shù),對(duì)于復(fù)雜函數(shù)催首,即使定義了內(nèi)聯(lián)編譯器可能也不會(huì)按照內(nèi)聯(lián)的方式進(jìn)行編譯扶踊。
- 內(nèi)聯(lián)函數(shù)相比宏定義更安全,內(nèi)聯(lián)函數(shù)可以檢查參數(shù)郎任,而宏定義只是簡(jiǎn)單的文本替換秧耗。因此推薦使用內(nèi)聯(lián)函數(shù),而不是宏定義舶治。
- 使用宏定義函數(shù)要特別注意給所有單元都加上括號(hào)分井,#define MUL(a, b) ab,這很危險(xiǎn)霉猛,正確寫(xiě)法:#define MUL(a, b) ((a)(b))
C++內(nèi)存管理
- C++內(nèi)存分為幾塊尺锚?
在C++中,內(nèi)存分成5個(gè)區(qū)惜浅,他們分別是堆瘫辩、棧、自由存儲(chǔ)區(qū)坛悉、全局/靜態(tài)存儲(chǔ)區(qū)和常量存儲(chǔ)區(qū)伐厌。
- 棧,在執(zhí)行函數(shù)時(shí)裸影,函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建挣轨,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中空民,效率很高刃唐,但是分配的內(nèi)存容量有限。
- 堆界轩,就是那些由new分配的內(nèi)存塊画饥,他們的釋放編譯器不去管,由我們的應(yīng)用程序去控制浊猾,一般一個(gè)new就要對(duì)應(yīng)一個(gè)delete抖甘。如果程序員沒(méi)有釋放掉,那么在程序結(jié)束后葫慎,操作系統(tǒng)會(huì)自動(dòng)回收衔彻。
- 自由存儲(chǔ)區(qū)薇宠,就是那些由malloc等分配的內(nèi)存塊,他和堆是十分相似的艰额,不過(guò)它是用free來(lái)結(jié)束自己的生命的澄港。
- 全局/靜態(tài)存儲(chǔ)區(qū),全局變量和靜態(tài)變量被分配到同一塊內(nèi)存中柄沮,在以前的C語(yǔ)言中回梧,全局變量又分為初始化的和未初始化的,在C++里面沒(méi)有這個(gè)區(qū)分了祖搓,他們共同占用同一塊內(nèi)存區(qū)狱意。
- 常量存儲(chǔ)區(qū),這是一塊比較特殊的存儲(chǔ)區(qū)拯欧,他們里面存放的是常量详囤,不允許修改
在此注意自由存儲(chǔ)區(qū)和堆
- 自由存儲(chǔ)是C++中通過(guò)new與delete動(dòng)態(tài)分配和釋放對(duì)象的抽象概念,而堆(heap)是C語(yǔ)言和操作系統(tǒng)的術(shù)語(yǔ)镐作,是操作系統(tǒng)維護(hù)的一塊動(dòng)態(tài)分配內(nèi)存藏姐。
- new所申請(qǐng)的內(nèi)存區(qū)域在C++中稱(chēng)為自由存儲(chǔ)區(qū)。借由堆實(shí)現(xiàn)的自由存儲(chǔ)滑肉,可以說(shuō)new所申請(qǐng)的內(nèi)存區(qū)域在堆上包各。
- 堆與自由存儲(chǔ)區(qū)還是有區(qū)別的,它們并非等價(jià)靶庙。
- 學(xué)會(huì)遷移问畅,可以說(shuō)到malloc,從malloc說(shuō)到操作系統(tǒng)的內(nèi)存管理六荒,說(shuō)道內(nèi)核態(tài)和用戶(hù)態(tài)护姆,然后就什么高端內(nèi)存,slab層掏击,伙伴算法卵皂,VMA可以巴拉巴拉了,接著可以遷移到fork()砚亭。
STL里的內(nèi)存管理
STL內(nèi)存分配分為一級(jí)分配器和二級(jí)分配器灯变,一級(jí)分配器就是采用malloc分配內(nèi)存,二級(jí)分配器采用內(nèi)存池捅膘。
二級(jí)分配器設(shè)計(jì)的非常巧妙添祸,分別給8k,16k,..., 128k等比較小的內(nèi)存片都維持一個(gè)空閑鏈表寻仗,每個(gè)鏈表的頭節(jié)點(diǎn)由一個(gè)數(shù)組來(lái)維護(hù)刃泌。需要分配內(nèi)存時(shí)從合適大小的鏈表中取一塊下來(lái)。假設(shè)需要分配一塊10K的內(nèi)存,那么就找到最小的大于等于10k的塊耙替,也就是16K亚侠,從16K的空閑鏈表里取出一個(gè)用于分配。釋放該塊內(nèi)存時(shí)俗扇,將內(nèi)存節(jié)點(diǎn)歸還給鏈表硝烂。
如果要分配的內(nèi)存大于128K則直接調(diào)用一級(jí)分配器。
為了節(jié)省維持鏈表的開(kāi)銷(xiāo)狐援,采用了一個(gè)union結(jié)構(gòu)體钢坦,分配器使用union里的next指針來(lái)指向下一個(gè)節(jié)點(diǎn),而用戶(hù)則使用union的空指針來(lái)表示該節(jié)點(diǎn)的地址啥酱。
STL里set和map是基于什么實(shí)現(xiàn)的?紅黑樹(shù)的特點(diǎn)厨诸?
STL的set和map都是基于紅黑樹(shù)實(shí)現(xiàn)的
AVL是一種高度平衡的二叉樹(shù)镶殷,所以通常的結(jié)果是,維護(hù)這種高度平衡所付出的代價(jià)比從中獲得的效率收益還大微酬,故而實(shí)際的應(yīng)用不多绘趋,更多的地方是用追求局部而不是非常嚴(yán)格整體平衡的紅黑樹(shù)。當(dāng)然颗管,如果場(chǎng)景中對(duì)插入刪除不頻繁陷遮,只是對(duì)查找特別有要求,AVL還是優(yōu)于紅黑的垦江。
紅黑樹(shù)的應(yīng)用:STL帽馋,epoll在內(nèi)核中的實(shí)現(xiàn)
- 每個(gè)結(jié)點(diǎn)或者為黑色或者為紅色。
- 根結(jié)點(diǎn)為黑色比吭。
- 每個(gè)葉結(jié)點(diǎn)(實(shí)際上就是NULL指針)都是黑色的绽族。
- 如果一個(gè)結(jié)點(diǎn)是紅色的,那么它的兩個(gè)子節(jié)點(diǎn)都是黑色的(也就是說(shuō)衩藤,不能有兩個(gè)相鄰的紅色結(jié)點(diǎn))吧慢。
- 對(duì)于每個(gè)結(jié)點(diǎn),從該結(jié)點(diǎn)到其所有子孫葉結(jié)點(diǎn)的路徑中所包含的黑色結(jié)點(diǎn)數(shù)量必須相同赏表。
紅黑樹(shù)能夠以O(shè)(log2 n) 的時(shí)間復(fù)雜度進(jìn)行搜索检诗、插入、刪除操作瓢剿。此外逢慌,由于它的設(shè)計(jì),任何不平衡都會(huì)在三次旋轉(zhuǎn)之內(nèi)解決跋选。當(dāng)然涕癣,還有一些更好的,但實(shí)現(xiàn)起來(lái)更復(fù)雜的數(shù)據(jù)結(jié)構(gòu),能夠做到一步旋轉(zhuǎn)之內(nèi)達(dá)到平衡坠韩,但紅黑樹(shù)能夠給我們一個(gè)比較“便宜”的解決方案距潘。紅黑樹(shù)的算法時(shí)間復(fù)雜度和AVL相同,但統(tǒng)計(jì)性能比AVL樹(shù)更高只搁。
如果插入一個(gè)node引起了樹(shù)的不平衡音比,AVL和RB-Tree都是最多只需要2次旋轉(zhuǎn)操作,即兩者都是O(1)氢惋;但是在刪除node引起樹(shù)的不平衡時(shí)洞翩,最壞情況下,AVL需要維護(hù)從被刪node到root這條路徑上所有node的平衡性焰望,因此需要旋轉(zhuǎn)的量級(jí)O(logN)骚亿,而RB-Tree最多只需3次旋轉(zhuǎn),只需要O(1)的復(fù)雜度熊赖。
必須在構(gòu)造函數(shù)初始化列表里進(jìn)行初始化的數(shù)據(jù)成員有哪些
- 常量成員来屠,因?yàn)槌A恐荒艹跏蓟荒苜x值,所以必須放在初始化列表里面
- 引用類(lèi)型震鹉,引用必須在定義的時(shí)候初始化俱笛,并且不能重新賦值旁仿,所以也要寫(xiě)在初始化列表里面
- 沒(méi)有默認(rèn)構(gòu)造函數(shù)的類(lèi)類(lèi)型汰瘫,因?yàn)槭褂贸跏蓟斜砜梢圆槐卣{(diào)用默認(rèn)構(gòu)造函數(shù)來(lái)初始化,而是直接調(diào)用拷貝構(gòu)造函數(shù)初始化
- 要注意神妹,對(duì)非內(nèi)置類(lèi)型成員浆兰,肯定還是列表的性能好磕仅,因?yàn)槭÷粤艘淮螐?fù)制的過(guò)程
模板特化
模板分為類(lèi)模板與函數(shù)模板,特化分為全特化與偏特化镊讼。全特化就是限定死模板實(shí)現(xiàn)的具體類(lèi)型宽涌,偏特化就是如果這個(gè)模板有多個(gè)類(lèi)型,那么只限定其中的一部分蝶棋。
模板特化的目的就是對(duì)于某一種變量類(lèi)型具有不同的實(shí)現(xiàn)卸亮,因此需要特化版本。例如玩裙,在STL里迭代器為了適應(yīng)原生指針就將原生指針進(jìn)行特化兼贸。
數(shù)據(jù)結(jié)構(gòu)和算法
手寫(xiě)strcpy
char* strcpy(char* dst, const char* src){
assert(dst);
assert(src);
char* p = dst;
while((*dst++ = *src++)!='\0') ;
return p;
}
若考慮重疊,則有:
char* strcpy(char* dst, const char* src){
assert(dst);
assert(src);
int size = strlen(src)+1;
char* p = dst;
if(dst > src && dst < src+size)
{
dst = dst + size - 1;
src = dst + size - 1;
while(size--)
*dst-- = *src--;
}
else
{
while(size--)
*dst++ = *src++;
}
return p;
}
手寫(xiě)memcpy函數(shù)
void* memcpy(void* dst, const void* src, size_t size){
if(dst == NULL || src == NULL)
return NULL;
void* p = dst;
char* pdst = (char*)dst;
char* psrc = (char*)src;
if(pdst>src && pdst<src+size)
{
pdst = pdst+size+1;
psrc = psrc+size+1;
while(size--)
*pdst-- = *psrc--;
}
else
{
while(size--)
*pdst++ = *psrc++;
}
return p;
}
手寫(xiě)strcat函數(shù)
char* strcat(char* dst, const char* src){
char* p = dst;
while(*dst != '\0')
dst++;
while(*dst++ = *src++ !='\0') ;
return p;
}
手寫(xiě)strcmp函數(shù)
int strcmp(const char* s1, const char* s2){
while(*s1 == *s2 && *s1!='\0'){
++s1;++s2;
}
return *s1-*s2;
}
Hash表
- 根據(jù)關(guān)鍵碼值(key value)直接訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)吃溅,實(shí)現(xiàn)有拉鏈法(鏈表)溶诞,以及開(kāi)放地址法解決沖突
- 開(kāi)放地址法常見(jiàn)策略:
- 線性探測(cè)
- 線性補(bǔ)償探測(cè)法
- 隨機(jī)探測(cè)
- 平方探測(cè)
STL中hash_map擴(kuò)容發(fā)生什么?
(1) 創(chuàng)建一個(gè)新桶决侈,該桶是原來(lái)桶兩倍大最接近的質(zhì)數(shù)(判斷n是不是質(zhì)數(shù)的方法:用n除2到$sqrt(n)$范圍內(nèi)的數(shù)) 螺垢;
(2) 將原來(lái)桶里的數(shù)通過(guò)指針的轉(zhuǎn)換,插入到新桶中(注意STL這里做的很精細(xì),沒(méi)有直接將數(shù)據(jù)從舊桶遍歷拷貝數(shù)據(jù)插入到新桶枉圃,而是通過(guò)指針轉(zhuǎn)換)
(3) 通過(guò)swap函數(shù)將新桶和舊桶交換功茴,銷(xiāo)毀新桶。Redis中hash擴(kuò)容孽亲?
容量擴(kuò)張是一次完成的坎穿,期間要花很長(zhǎng)時(shí)間一次轉(zhuǎn)移hash表中的所有元素。
redis中的dict.c中的設(shè)計(jì)思路是用兩個(gè)hash表來(lái)進(jìn)行進(jìn)行擴(kuò)容和轉(zhuǎn)移的工作返劲,把第一個(gè)hash表所有元素的轉(zhuǎn)移分?jǐn)倿槎啻无D(zhuǎn)移玲昧,而且每次轉(zhuǎn)移的期望時(shí)間復(fù)雜度為O(1)。這樣就不會(huì)出現(xiàn)某一次往字典中插入元素要等候很長(zhǎng)時(shí)間的情況了篮绿。
樹(shù)
- 二叉樹(shù)結(jié)構(gòu)孵延,二叉搜索樹(shù)在二叉樹(shù)的基礎(chǔ)上加上了這樣的一個(gè)性質(zhì):對(duì)于樹(shù)中的每一個(gè)節(jié)點(diǎn)來(lái)說(shuō),如果有左兒子的話搔耕,它的左兒子的值一定小于它本身的值隙袁,如果有右兒子的話,它的右兒子的值一定大于它本身的值弃榨。
- 二叉樹(shù)的六種遍歷(遞歸,非遞歸)
- 二叉樹(shù)的層序遍歷
- 遞歸是解決二叉樹(shù)相關(guān)問(wèn)題的神級(jí)方法
- 樹(shù)的各種常見(jiàn)算法題
什么是紅黑樹(shù)
- 節(jié)點(diǎn)為紅色或黑色
- 根節(jié)點(diǎn)為黑色
- 每個(gè)葉節(jié)點(diǎn)(NIL節(jié)點(diǎn)梨睁,空節(jié)點(diǎn))是黑色的
- 每個(gè)紅色節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn)都是黑色的(也就是說(shuō)不存在兩個(gè)連續(xù)的紅色節(jié)點(diǎn))
- 從任一節(jié)點(diǎn)到其每個(gè)葉節(jié)點(diǎn)的所有路徑都包含相同數(shù)目的黑色節(jié)點(diǎn)
紅黑樹(shù)與AVL樹(shù)的區(qū)別
- 紅黑樹(shù)與AVL樹(shù)都是平衡樹(shù)鲸睛,但是AVL是完全平衡的(平衡就是值樹(shù)中任意節(jié)點(diǎn)的左子樹(shù)和右子樹(shù)高度差不超過(guò)1);
- 紅黑樹(shù)插入效率更高坡贺,因?yàn)锳VL為了保證其完全平衡官辈,插入和刪除的時(shí)候在最壞的情況下要旋轉(zhuǎn)logN次,而紅黑樹(shù)插入和刪除的旋轉(zhuǎn)次數(shù)要比AVL少遍坟,犧牲了嚴(yán)格的高度平衡的優(yōu)越條件使得三次旋轉(zhuǎn)即可平衡拳亿。
鏈表
- 鏈表的插入和刪除,單向雙向鏈表
- 鏈表的問(wèn)題考慮多個(gè)指針和遞歸
- 反向打印鏈表(遞歸)
- 打印倒數(shù)第K個(gè)節(jié)點(diǎn)(前后指針)
- 鏈表是否有環(huán)(快慢指針)
棧和隊(duì)列
棧(Stack)和隊(duì)列(Queue)是兩種操作受限的線性表愿伴。
相同點(diǎn):
1. 都是線性結(jié)構(gòu)肺魁。
2. 插入操作都是限定在表尾進(jìn)行。
3. 都可以通過(guò)順序結(jié)構(gòu)和鏈?zhǔn)浇Y(jié)構(gòu)實(shí)現(xiàn)隔节。鹅经、
4. 插入與刪除的時(shí)間復(fù)雜度都是O(1),在空間復(fù)雜度上兩者也一樣怎诫。
5. 多鏈棧和多鏈隊(duì)列的管理模式可以相同瘾晃。
不同點(diǎn):
- 刪除數(shù)據(jù)元素的位置不同,棧的刪除操作在表尾進(jìn)行幻妓,隊(duì)列的刪除操作在表頭進(jìn)行蹦误。
- 應(yīng)用場(chǎng)景不同:
棧的應(yīng)用場(chǎng)景包括括號(hào)問(wèn)題的求解,表達(dá)式的轉(zhuǎn)換和求值,函數(shù)調(diào)用和遞歸實(shí)現(xiàn)强胰,深度優(yōu)先搜索遍歷等
隊(duì)列的應(yīng)用場(chǎng)景包括計(jì)算機(jī)系統(tǒng)中各種資源的管理舱沧,消息緩沖器的管理和廣度優(yōu)先搜索遍歷等。 - 順序棧能夠?qū)崿F(xiàn)多椖睦空間共享狗唉,而順序隊(duì)列不能。
海量數(shù)據(jù)問(wèn)題
類(lèi)似問(wèn)題的解決方法思路:首先哈希將數(shù)據(jù)分成N個(gè)文件涡真,然后對(duì)每個(gè)文件建立K個(gè)元素最小/大堆(根據(jù)要求來(lái)選擇)分俯。最后將文件中剩余的數(shù)插入堆中,并維持K個(gè)元素的堆哆料。最后將N個(gè)堆中的元素合起來(lái)分析缸剪。可以采用歸并的方式來(lái)合并东亦。在歸并的時(shí)候?yàn)榱颂岣咝蔬€需要建一個(gè)N個(gè)元素構(gòu)成的最大堆杏节,先用N個(gè)堆中的最大值填充這個(gè)堆,然后就是彈出最大值典阵,指針后移的操作了奋渔。當(dāng)然這種問(wèn)題在現(xiàn)在的互聯(lián)網(wǎng)技術(shù)中,一般就用map-reduce框架來(lái)做了壮啊。
大數(shù)據(jù)排序相同的思路:先哈希(哈希是好處是分布均勻嫉鲸,相同的數(shù)在同一個(gè)文件中),然后小文件裝入內(nèi)存快排歹啼,排序結(jié)果輸出到文件玄渗。最后建堆歸并。
海量數(shù)據(jù)重復(fù)問(wèn)題
使用hash_map或者位圖狸眼,再利用歸并的思想
排序算法
- 必須至少能快速寫(xiě)出藤树,快排,建堆拓萌,和歸并
- 種算法的時(shí)間空間復(fù)雜度岁钓,最好最差平均情況
位運(yùn)算
- 左移乘2,右移除2
- 不用臨時(shí)變量交換兩個(gè)整數(shù)(多次異或)
- 消除最后一個(gè)1
- 不用加減乘除完成整數(shù)相加
布隆過(guò)濾器
由一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)組成司志,布隆過(guò)濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中甜紫。
優(yōu)點(diǎn)是空間效率和查詢(xún)時(shí)間都遠(yuǎn)遠(yuǎn)超過(guò)一般的算法,缺點(diǎn)是有一定的誤識(shí)別率(但是不會(huì)漏報(bào))
網(wǎng)絡(luò)與TCP/IP
TCP與UDP的區(qū)別
IP首部骂远,TCP首部囚霸,UDP首部
-
TCP和UDP區(qū)別
- TCP基于有連接,UDP基于無(wú)連接
- TCP能保證可靠傳輸激才,UDP不能保證可靠傳輸TCP
- TCP結(jié)構(gòu)復(fù)雜拓型,消耗資源多额嘿,建立過(guò)程較慢較復(fù)雜。UDP結(jié)構(gòu)簡(jiǎn)單劣挫,消耗資源少册养,建立過(guò)程較快
- TCP基于流模式,UDP是數(shù)據(jù)報(bào)模式
- TCP連接只能是點(diǎn)到點(diǎn)压固,而UDP可以一對(duì)一球拦,一對(duì)多或者多對(duì)多
- TCP有確認(rèn),重傳帐我,擁賽控制機(jī)制坎炼,UDP在沒(méi)有建立連接或者對(duì)方已經(jīng)退出的情況下任然會(huì)繼續(xù)發(fā)送數(shù)據(jù),導(dǎo)致通信流量的浪費(fèi)拦键。
TCP和UDP應(yīng)用場(chǎng)景
- TCP:用于實(shí)現(xiàn)可靠傳輸?shù)那闆r谣光,文件非常重要,對(duì)網(wǎng)絡(luò)擁堵有較高要求的情況芬为。
- UDP:用于高速傳輸和實(shí)時(shí)性較高的場(chǎng)合(即時(shí)通信)萄金,廣播通信
- 實(shí)現(xiàn)UDP的可靠傳輸,如RTP協(xié)議媚朦,RUDP協(xié)議
檢測(cè)包的順序氧敢,請(qǐng)求重傳,請(qǐng)求者發(fā)起或接收者發(fā)起
TCP三次握手與四次揮手
建立連接
- 客戶(hù)端發(fā)送請(qǐng)求包询张,告訴服務(wù)器:“我想和你通信福稳?”數(shù)據(jù)包中SYN位置為1,假設(shè)其序列號(hào)為x瑞侮,客戶(hù)端狀態(tài)變成SYN_SENT;
- 服務(wù)器端接受到請(qǐng)求包后也發(fā)送一個(gè)請(qǐng)求包鼓拧,告訴客戶(hù)端:“現(xiàn)在可以建立連接”半火。數(shù)據(jù)包中SYN位置位1,假設(shè)其序列號(hào)為y季俩,注意客戶(hù)端序列號(hào)和服務(wù)器端序列號(hào)并沒(méi)有關(guān)系钮糖,他們是由各自的內(nèi)核按照一定的規(guī)則生成的。但是這個(gè)應(yīng)答包的32位應(yīng)答號(hào)酌住,必須是x+1店归,之所以加1是因?yàn)榭蛻?hù)端發(fā)過(guò)來(lái)的包SYN位被認(rèn)為占一個(gè)數(shù)據(jù)。因此酪我,告訴下一包從x+1開(kāi)始發(fā)消痛。發(fā)送后,服務(wù)器從監(jiān)聽(tīng)狀態(tài)變成SYN_RCVD狀態(tài)都哭。
- 客戶(hù)端發(fā)送應(yīng)答數(shù)據(jù)包秩伞,告訴服務(wù)器:“那我們開(kāi)始發(fā)送數(shù)據(jù)吧”逞带。數(shù)據(jù)包應(yīng)答號(hào)為y+1∩葱拢客戶(hù)端變成ESTABLISHED狀態(tài)展氓,即可以傳輸狀態(tài)。
- 服務(wù)器端接受到應(yīng)答數(shù)據(jù)包后脸爱,變成ESTABLISHED狀態(tài)遇汞。
發(fā)送數(shù)據(jù)
發(fā)送數(shù)據(jù)
- 客戶(hù)端發(fā)送一個(gè)一個(gè)字節(jié)的數(shù)據(jù),因此序列號(hào)為x+1簿废;
- 服務(wù)端發(fā)送一個(gè)應(yīng)答包空入,應(yīng)答號(hào)為x+2,告訴客戶(hù)端下次從x+2開(kāi)始發(fā)捏鱼;
斷開(kāi)連接
- 客戶(hù)端發(fā)送請(qǐng)求斷開(kāi)的數(shù)據(jù)包执庐,告訴服務(wù)器:“數(shù)據(jù)傳完了,我要斷開(kāi)了”导梆。發(fā)送一個(gè)FIN包轨淌,序列號(hào)x+2】茨幔客戶(hù)端轉(zhuǎn)移到FIN_WAIT_1狀態(tài)递鹉。
- 服務(wù)器端發(fā)送應(yīng)答包,告訴客戶(hù)端:“行藏斩,我知道了躏结,你斷開(kāi)吧!”狰域。應(yīng)答號(hào)為x+3媳拴,服務(wù)器進(jìn)入CLOSE_WAIT狀態(tài)≌桌溃客戶(hù)端收到應(yīng)答后屈溉,轉(zhuǎn)移到FIN_WAIT_2狀態(tài)。
- 服務(wù)器發(fā)送一個(gè)斷開(kāi)數(shù)據(jù)包抬探,告訴客戶(hù)端:“既然傳完了子巾,那我這邊的開(kāi)關(guān)也準(zhǔn)備關(guān)了”。序列號(hào)為y+1小压,發(fā)送完后服務(wù)器進(jìn)入LAST_ACK狀態(tài)线梗。
- 客戶(hù)端發(fā)送一個(gè)應(yīng)答包,告訴服務(wù)器:“好的怠益,我知道你要斷開(kāi)了仪搔。”應(yīng)答號(hào)為y+2溉痢∑г欤客戶(hù)端進(jìn)入TIME_WAIT狀態(tài)憋他。
TIME_WAIT又稱(chēng)為2MSL等待狀態(tài),MSL是系統(tǒng)中定義的最大報(bào)文生存時(shí)間髓削,任何TCP報(bào)文在網(wǎng)絡(luò)中生存時(shí)間超過(guò)這個(gè)值就必須被丟棄竹挡。
等待MSL的原因是防止最后一個(gè)ACK丟失后可以進(jìn)行重發(fā),如果ACK丟失后立膛,服務(wù)器會(huì)重發(fā)FIN揪罕。
MSL是Maximum Segment Lifetime英文的縮寫(xiě),中文可以譯為“報(bào)文最大生存時(shí)間”
TCP相關(guān)技術(shù)
TCP重發(fā)機(jī)制
- 超時(shí)重傳(RTO)
當(dāng)一個(gè)包被發(fā)送后宝泵,就開(kāi)啟一個(gè)定時(shí)器好啰,如果定時(shí)時(shí)間到了,還未收到能確認(rèn)該發(fā)送包的應(yīng)答包儿奶,就重傳一份數(shù)據(jù)框往。注意收到的應(yīng)答包可能是該包也可能是后面包的,但是只要能確認(rèn)該包被收到就行闯捎。另外如果椰弊,是因?yàn)榫W(wǎng)絡(luò)延時(shí)造成重傳,則接受端收到重復(fù)數(shù)據(jù)包后丟棄該包瓤鼻。 - 快速重傳
當(dāng)如果發(fā)送端收到一個(gè)包的三次應(yīng)答包后秉版,立即重傳,比超時(shí)重傳更高效茬祷。
Nagle算法
核心思想為任意時(shí)刻清焕,最多只能有一個(gè)未被確認(rèn)的小段。 所謂“小段”祭犯,指的是小于MSS尺寸的數(shù)據(jù)塊秸妥,所謂“未被確認(rèn)”,是指一個(gè)數(shù)據(jù)塊發(fā)送出去后沃粗,沒(méi)有收到對(duì)方發(fā)送的ACK確認(rèn)該數(shù)據(jù)已收到筛峭。
Nagle算法簡(jiǎn)單講就是,等待服務(wù)器應(yīng)答包到達(dá)后陪每,再發(fā)送下一個(gè)數(shù)據(jù)包。數(shù)據(jù)在發(fā)送端被緩存镰吵,如果緩存到達(dá)指定大小就將其發(fā)送檩禾,或者上一個(gè)數(shù)據(jù)的應(yīng)答包到達(dá),將緩存區(qū)一次性全部發(fā)送疤祭。
Nagle算法是從發(fā)送端角度考慮減少了數(shù)據(jù)包的個(gè)數(shù)盼产,時(shí)延應(yīng)答從接收端角度考慮減少了數(shù)據(jù)包的個(gè)數(shù)。
TCP流量控制
目的:如果發(fā)送方把數(shù)據(jù)發(fā)送得過(guò)快勺馆,接收方可能會(huì)來(lái)不及接收戏售,這就會(huì)造成數(shù)據(jù)的丟失侨核。
所以流量控制是點(diǎn)對(duì)點(diǎn)通信的控制,而擁塞控制是對(duì)整個(gè)網(wǎng)絡(luò)內(nèi)流量負(fù)載的控制
TCP的流量控制是利用滑動(dòng)窗口機(jī)制實(shí)現(xiàn)的灌灾,接收方在返回的ACK中會(huì)包含自己的接收窗口的大小搓译,以控制發(fā)送方的數(shù)據(jù)發(fā)送。
如上圖所示A向B發(fā)送數(shù)據(jù)锋喜。在連接建立時(shí)些己,B告訴A接收窗口rwnd(receiver window)= 400,單位字節(jié)嘿般,因此發(fā)送方A的發(fā)送窗口不能超過(guò)400段标。
(可以看出,B向A發(fā)送的三個(gè)報(bào)文段都設(shè)置了 ACK = 1以保證字段有效炉奴,后面的rwnd值就是接收方對(duì)發(fā)送方的三次流量控制逼庞。)
第一次把窗口設(shè)置為300 ,第二次100 瞻赶,最后一次為 0赛糟,即不允許發(fā)送方再發(fā)送數(shù)據(jù)的狀態(tài)。
但是當(dāng)某個(gè)ACK報(bào)文丟失了共耍,就會(huì)出現(xiàn)A等待B確認(rèn)虑灰,并且B等待A發(fā)送數(shù)據(jù)的死鎖狀態(tài)。為了解決這種問(wèn)題痹兜,TCP引入了持續(xù)計(jì)時(shí)器(Persistence timer)穆咐,當(dāng)A收到rwnd=0時(shí),就啟用該計(jì)時(shí)器字旭,時(shí)間到了則發(fā)送一個(gè)1字節(jié)的探測(cè)報(bào)文对湃,詢(xún)問(wèn)B是很忙還是上個(gè)ACK丟失了,然后B回應(yīng)自身的接收窗口大小遗淳,返回仍為0(A重設(shè)持續(xù)計(jì)時(shí)器繼續(xù)等待)或者會(huì)重發(fā)rwnd=x拍柒。
TCP窗口滑動(dòng)
窗口是TCP中為了解決應(yīng)答機(jī)制等待時(shí)間過(guò)長(zhǎng)而引入的方法,如果沒(méi)有窗口屈暗,則TCP每發(fā)送一次數(shù)據(jù)就必須等待應(yīng)答拆讯,收到應(yīng)答后繼續(xù)發(fā)送,如果沒(méi)有收到則等待一段時(shí)間后重發(fā)养叛,如果很長(zhǎng)時(shí)間都無(wú)法收到應(yīng)答則判斷為網(wǎng)絡(luò)斷開(kāi)种呐。而使用窗口后,窗口的大小指無(wú)需等待應(yīng)答可以連續(xù)發(fā)送多個(gè)數(shù)據(jù)包弃甥。
TCP窗口在每個(gè)傳輸方向都有兩個(gè)窗口爽室,發(fā)送端窗口和接收端窗口,又因?yàn)門(mén)CP是全雙工通信淆攻,因此有四個(gè)窗口阔墩。
引入窗口后嘿架,TCP的應(yīng)答包如果部分丟失,無(wú)需重傳啸箫,由后面的應(yīng)答包保證耸彪。TCP為了提高效率,采用延時(shí)再確認(rèn)應(yīng)答筐高,和選擇性確認(rèn)應(yīng)答搜囱,即收到數(shù)據(jù)包后不立即發(fā)送應(yīng)答包,而是等待收到下一個(gè)或多個(gè)包后發(fā)一個(gè)應(yīng)答柑土。
TCP的擁塞控制算法和過(guò)程
網(wǎng)絡(luò)中的鏈路容量蜀肘、交換結(jié)點(diǎn)中的緩存、處理機(jī)等等都有著工作的極限稽屏,當(dāng)網(wǎng)絡(luò)的需求超過(guò)它們的工作極限時(shí)扮宠,就出現(xiàn)了擁塞。擁塞控制就是防止過(guò)多的數(shù)據(jù)注入到網(wǎng)絡(luò)中狐榔,這樣可以使網(wǎng)絡(luò)中的路由器或鏈路不致過(guò)載坛增。
慢開(kāi)始(Slow-Start)和擁塞避免(Congestion Avoidance)結(jié)合
慢開(kāi)始算法是指開(kāi)始發(fā)送數(shù)據(jù)時(shí),并不清楚網(wǎng)絡(luò)的負(fù)荷情況薄腻,會(huì)先發(fā)送一個(gè)1字節(jié)的試探報(bào)文收捣,當(dāng)收到確認(rèn)后,就發(fā)送2個(gè)字節(jié)的報(bào)文庵楷,繼而4個(gè)罢艾,8個(gè)以此指數(shù)類(lèi)推。
需要注意的是尽纽,慢開(kāi)始的“慢”并不是指擁塞窗口的增長(zhǎng)速率慢,而是指在TCP開(kāi)始發(fā)送報(bào)文時(shí)先設(shè)置擁塞窗口=1。
擁塞避免算法是讓擁塞窗口緩慢地增大,即cwnd加1能庆,而不是如慢開(kāi)始算法一樣加倍邮绿。、
根據(jù)上圖的實(shí)例進(jìn)行分析,一開(kāi)始的慢開(kāi)始算法的指數(shù)增長(zhǎng)是很恐怖的吗垮,所以為了防止擁塞窗口cwnd增長(zhǎng)過(guò)快需要設(shè)置一個(gè)門(mén)限ssthresh,這里是16饵沧。
- 當(dāng) cwnd < ssthresh 時(shí),使用上述的慢開(kāi)始算法。
- 當(dāng) cwnd > ssthresh 時(shí),停止使用慢開(kāi)始算法而改用擁塞避免算法。
- 當(dāng) cwnd = ssthresh 時(shí),既可使用慢開(kāi)始算法,也可使用擁塞控制避免算法。
對(duì)超時(shí)事件作出反應(yīng)
在上述對(duì)擁塞窗口的描述中细溅,我們只是說(shuō)在連接開(kāi)始的時(shí)候,以指數(shù)級(jí)的速率增加儡嘶,直到第一個(gè)丟失事件發(fā)生。但實(shí)際中TCP對(duì)因超時(shí)而檢測(cè)到的丟包事件作出的反應(yīng)與對(duì)因收到3個(gè)冗余ACK而檢測(cè)到的丟包事件做出的反應(yīng)是不同的誓篱。
- 收到3個(gè)冗余ACK后:CongWin減半凯楔、窗口再線性增加窜骄。
- 檢測(cè)超時(shí)事件后:CongWin值設(shè)置為1MSS啼辣、窗口再指數(shù)增長(zhǎng)富弦、到達(dá)一個(gè)閾值(Threshold济似,初始化時(shí)被設(shè)置為一個(gè)很大的值盏缤,以使它沒(méi)有初始效應(yīng)砰蠢。每發(fā)生一個(gè)丟包事件,Threshold就會(huì)被設(shè)置為當(dāng)前CongWin值的一半)后唉铜,再線性增長(zhǎng)台舱。
原因:3個(gè)冗余ACK指示網(wǎng)絡(luò)還具有某些傳送報(bào)文段的能力;3個(gè)冗余ACK以前的超時(shí),則更為 “嚴(yán)重”潭流。
小結(jié):
- 當(dāng)CongWin < Threshold時(shí)竞惋,發(fā)送者處于慢啟動(dòng)階段, CongWin指數(shù)增長(zhǎng)。
- 當(dāng)CongWin > Threshold時(shí)灰嫉,發(fā)送者處于擁塞避免階段, CongWin線性增長(zhǎng)拆宛。
- 當(dāng)出現(xiàn)3個(gè)冗余確認(rèn)時(shí), 閾值Threshold設(shè)置為CongWin/2,且CongWin設(shè)置為T(mén)hreshold讼撒。
- 當(dāng)超時(shí)發(fā)生時(shí)浑厚,閾值Threshold設(shè)置為CongWin/2股耽,并且CongWin設(shè)置為1 MSS.
快重傳(Fast Retransmit)和快恢復(fù)(Fast Recovery)結(jié)合
快重傳是指,如果發(fā)送端接收到3個(gè)以上的重復(fù)ACK钳幅,不需要等到重傳定時(shí)器溢出就重新傳遞豺谈,所以叫做快速重傳,而快速重傳以后贡这,因?yàn)樽叩牟皇锹龁?dòng)而是擁塞避免算法,所以這又叫做快速恢復(fù)算法厂榛。
如果沒(méi)有快速重傳和快速恢復(fù)盖矫,TCP將會(huì)使用定時(shí)器來(lái)要求傳輸暫停。在暫停這段時(shí)間內(nèi)击奶,沒(méi)有新的數(shù)據(jù)包被發(fā)送辈双。所以快速重傳和快速恢復(fù)旨在快速恢復(fù)丟失的數(shù)據(jù)包。
與快重傳配合使用的還有快恢復(fù)算法柜砾,結(jié)合下圖的實(shí)例來(lái)分析湃望,其過(guò)程有以下兩個(gè)要點(diǎn):
- 當(dāng)發(fā)送方在cwnd=24時(shí)連續(xù)收到三個(gè)重復(fù)確認(rèn),就把慢開(kāi)始門(mén)限ssthresh減半(就是上圖中的24修改為12)痰驱。
- 接下來(lái)不執(zhí)行慢開(kāi)始算法证芭,而是把cwnd值設(shè)置為門(mén)限ssthresh減半后的數(shù)值(即cwnd不是設(shè)置為1而是設(shè)置為12),然后開(kāi)始執(zhí)行的是擁塞避免算法担映,使擁塞窗口緩慢地線性增大废士。
這里為什么替換掉了慢開(kāi)始算法呢?
這是因?yàn)槭盏街貜?fù)的ACK不僅僅告訴我們一個(gè)分組丟失了蝇完,由于接收方只有在收到另一個(gè)報(bào)文段時(shí)才會(huì)產(chǎn)生重復(fù)的ACK官硝,所以還告訴我們?cè)搱?bào)文段已經(jīng)進(jìn)入了接收方的緩存。也就是說(shuō)短蜕,在收發(fā)兩端之間仍然有流動(dòng)的數(shù)據(jù)氢架,而我們不想執(zhí)行慢啟動(dòng)來(lái)突然減少數(shù)據(jù)流。
TCP客戶(hù)與服務(wù)器模型朋魔,用到哪些函數(shù)
服務(wù)端:
- 創(chuàng)建套接字:int socket(int family,int type,int protocol);返回:非負(fù)描述字---成功 -1---失敗
- 綁定套接字:把一個(gè)套接字地址(本機(jī)IP和端口號(hào))綁定到創(chuàng)建的套接字上
int bind(int sockfd, const struct sockaddr * server, socklen_t addrlen);
返回:0---成功 -1---失敗 - 監(jiān)聽(tīng)套接字:int listen(int sockfd, int backlog);backlog是已完成隊(duì)列和未完成隊(duì)列大小之和
- 等待來(lái)自客戶(hù)端的連接請(qǐng)求:int accept(int listenfd, struct sockaddr *client, socklen_t * addrlen); 返回已連接描述符
- 數(shù)據(jù)傳輸:
int write(int sockfd, char *buf, int len);
int read(int sockfd, char *buf, intlen);
send和recv函數(shù):TCP套接字提供了send()和recv()函數(shù)岖研,用來(lái)發(fā)送和接收操作。這兩個(gè)函數(shù)與write()和read()函數(shù)很相似铺厨,只是多了一個(gè)附加的傳輸控制參數(shù)室谚。 - 關(guān)閉套接字:int close(int sockfd);
客戶(hù)端:
- 連接服務(wù)器:int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);
返回:0---成功 -1---失敗
UDP客戶(hù)與服務(wù)器模型抱究,用到哪些函數(shù)
UDP與TCP相比要簡(jiǎn)潔很多,UDP不需要listen,accept和connect過(guò)程桌硫。
- socket函數(shù)創(chuàng)建套接字
sockfd = socket(AF_INET, SOCK_DGRAM, 0); - bind函數(shù)殖蚕,綁定服務(wù)器地址到套接字上
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); - sendto函數(shù)锐膜,發(fā)送數(shù)據(jù)給指定地址
sendto函數(shù)比send函數(shù)多出兩個(gè)參數(shù),一個(gè)是目的地址,一個(gè)是地址長(zhǎng)度值骇。告訴客戶(hù)端發(fā)送給哪個(gè)IP地址和哪個(gè)端口號(hào)莹菱。 - recvfrom函數(shù),接收數(shù)據(jù)
recvfrom函數(shù)比recv函數(shù)多出兩個(gè)參數(shù)吱瘩,相當(dāng)于TCP的accept函數(shù)道伟,告訴我們是誰(shuí)發(fā)送了數(shù)據(jù)過(guò)來(lái)。
域名解析過(guò)程使碾,ARP的機(jī)制蜜徽,RARP的實(shí)現(xiàn)
ARP(地址解析協(xié)議)
ARP協(xié)議是輔助鏈路層傳輸?shù)模谝呀?jīng)知道下一站路由器的IP地址后票摇,要將以太網(wǎng)包發(fā)送給目的地址拘鞋,但是以太網(wǎng)需要的是目的mac地址不是IP地址,而通過(guò)ARP請(qǐng)求包就可以獲得目的IP地址的mac地址矢门。
ARP請(qǐng)求的過(guò)程:源主機(jī)以廣播的形式盆色,發(fā)送一個(gè)ARP請(qǐng)求包,所有與源主機(jī)在直連的主機(jī)都會(huì)收到一個(gè)請(qǐng)求包祟剔,如下圖所示隔躲,請(qǐng)求包詢(xún)問(wèn)目的IP地址的mac地址,目的IP地址的主機(jī)收到這個(gè)請(qǐng)求后峡扩,發(fā)送一個(gè)ARP應(yīng)答蹭越,告訴源主機(jī)自己的mac地址。
RARP以與ARP相反的方式工作教届。RARP發(fā)出要反向解析的物理地址并希望返回其對(duì)應(yīng)的IP地址响鹃,應(yīng)答包括由能夠提供所需信息的RARP服務(wù)器發(fā)出的IP地址。
Ping和TraceRoute實(shí)現(xiàn)原理
- Ping是通過(guò)發(fā)送ICMP報(bào)文回顯請(qǐng)求實(shí)現(xiàn)案训。
ICMP是(Internet Control Message Protocol)Internet控制報(bào)文協(xié)議,用于在IP主機(jī)买置、路由器之間傳遞控制消息。 - Tracert 命令用 IP 生存時(shí)間 (TTL) 字段和 ICMP 錯(cuò)誤消息來(lái)確定從一個(gè)主機(jī)到網(wǎng)絡(luò)上其他主機(jī)的路由强霎。
- 首先忿项,tracert送出一個(gè)TTL是1的IP 數(shù)據(jù)包到目的地,當(dāng)路徑上的第一個(gè)路由器收到這個(gè)數(shù)據(jù)包時(shí)城舞,它將TTL減1轩触。此時(shí),TTL變?yōu)?家夺,所以該路由器會(huì)將此數(shù)據(jù)包丟掉脱柱,并送回一個(gè)「ICMP time exceeded」消息(包括發(fā)IP包的源地址,IP包的所有內(nèi)容及路由器的IP地址)拉馋,tracert 收到這個(gè)消息后榨为,便知道這個(gè)路由器存在于這個(gè)路徑上惨好,接著tracert 再送出另一個(gè)TTL是2 的數(shù)據(jù)包,發(fā)現(xiàn)第2 個(gè)路由器...... tracert 每次將送出的數(shù)據(jù)包的TTL 加1來(lái)發(fā)現(xiàn)另一個(gè)路由器随闺,這個(gè)重復(fù)的動(dòng)作一直持續(xù)到某個(gè)數(shù)據(jù)包 抵達(dá)目的地日川。當(dāng)數(shù)據(jù)包到達(dá)目的地后,該主機(jī)則不會(huì)送回ICMP time exceeded消息矩乐,一旦到達(dá)目的地龄句,由于tracert通過(guò)UDP數(shù)據(jù)包向不常見(jiàn)端口(30000以上)發(fā)送數(shù)據(jù)包,因此會(huì)收到「ICMP port unreachable」消息散罕,故可判斷到達(dá)目的地撒璧。
- tracert 有一個(gè)固定的時(shí)間等待響應(yīng)(ICMP TTL到期消息)。如果這個(gè)時(shí)間過(guò)了笨使,它將打印出一系列的*號(hào)表明:在這個(gè)路徑上,這個(gè)設(shè)備不能在給定的時(shí)間內(nèi)發(fā)出ICMP TTL到期消息的響應(yīng)僚害。然后硫椰,Tracert給TTL記數(shù)器加1,繼續(xù)進(jìn)行萨蚕。
HTTP
HTTP/HTTPS 1.0靶草、1.1、2.0
HTTP的主要特點(diǎn)
- 簡(jiǎn)單快速:當(dāng)客戶(hù)端向服務(wù)器端發(fā)送請(qǐng)求時(shí)岳遥,只是簡(jiǎn)單的填寫(xiě)請(qǐng)求路徑和請(qǐng)求方法即可
- 靈活:HTTP 協(xié)議允許客戶(hù)端和服務(wù)器端傳輸任意類(lèi)型任意格式的數(shù)據(jù)對(duì)象
- 無(wú)連接:無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求奕翔。服務(wù)器處理完客戶(hù)的請(qǐng)求,并收到客戶(hù)的應(yīng)答后浩蓉,即斷開(kāi)連接派继,采用這種方式可以節(jié)省傳輸時(shí)間。(當(dāng)今多數(shù)服務(wù)器支持Keep-Alive功能捻艳,使用服務(wù)器支持長(zhǎng)連接驾窟,解決無(wú)連接的問(wèn)題)
- 無(wú)狀態(tài):無(wú)狀態(tài)是指協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力,服務(wù)器不知道客戶(hù)端是什么狀態(tài)认轨。即客戶(hù)端發(fā)送HTTP請(qǐng)求后绅络,服務(wù)器根據(jù)請(qǐng)求,會(huì)給我們發(fā)送數(shù)據(jù)嘁字,發(fā)送完后恩急,不會(huì)記錄信息。(使用 cookie 機(jī)制可以保持 session纪蜒,解決無(wú)狀態(tài)的問(wèn)題)
HTTP 1.1 的特點(diǎn)
- 默認(rèn)持久連接節(jié)省通信量衷恭,只要客戶(hù)端服務(wù)端任意一端沒(méi)有明確提出斷開(kāi)TCP連接,就一直保持連接霍掺,可以發(fā)送多次HTTP請(qǐng)求
- 管線化匾荆,客戶(hù)端可以同時(shí)發(fā)出多個(gè)HTTP請(qǐng)求拌蜘,而不用一個(gè)個(gè)等待響應(yīng)
- 斷點(diǎn)續(xù)傳
http2.0的特點(diǎn)
- HTTP/2采用二進(jìn)制格式而非文本格式
- HTTP/2是完全多路復(fù)用的,而非有序并阻塞的——只需一個(gè)HTTP連接就可以實(shí)現(xiàn)多個(gè)請(qǐng)求響應(yīng)
- 使用報(bào)頭壓縮牙丽,HTTP/2降低了開(kāi)銷(xiāo)
- HTTP/2讓服務(wù)器可以將響應(yīng)主動(dòng)“推送”到客戶(hù)端緩存中
GET和POST的區(qū)別
本質(zhì)上
- GET是向服務(wù)器索取數(shù)據(jù)的請(qǐng)求
- POST是向服務(wù)器提交數(shù)據(jù)的請(qǐng)求
- GET是等冪的简卧,POST不是等冪的,等冪就是一次執(zhí)行和多次執(zhí)行效果一樣烤芦!DELETE举娩,PUT,HEAD构罗,也是等冪的铜涉,由于網(wǎng)絡(luò)是不可靠的,安全性和等冪性就特別重要遂唧,如果POST兩次相同的芙代,會(huì)產(chǎn)生兩個(gè)資源。
表現(xiàn)上
- GET盖彭,服務(wù)器端用request.QueryString獲取變量的值纹烹,POST,服務(wù)器端用request.Form獲取數(shù)據(jù)
- get傳輸數(shù)據(jù)是通過(guò)URL請(qǐng)求召边,以field(字段)= value的形式铺呵,置于URL后,并用"?"連接隧熙,多個(gè)請(qǐng)求數(shù)據(jù)間用"&"連接片挂,如http://127.0.0.1/Test/login.action?name=admin&password=admin,這個(gè)過(guò)程用戶(hù)是可見(jiàn)的贞盯;post傳輸數(shù)據(jù)通過(guò)Http的post機(jī)制音念,將字段與對(duì)應(yīng)值封存在請(qǐng)求實(shí)體中發(fā)送給服務(wù)器,這個(gè)過(guò)程對(duì)用戶(hù)是不可見(jiàn)的躏敢;
- GET安全性低症昏,用戶(hù)可見(jiàn),POST安全性高些
- GET效率高些父丰,只發(fā)送一次數(shù)據(jù)包肝谭,POST會(huì)發(fā)送兩次TCP數(shù)據(jù)包(先header,再data)
- 數(shù)據(jù)量大卸晟取:URL不存在參數(shù)上限攘烛,取決于特定的瀏覽器或服務(wù)器限制,POST數(shù)據(jù)理論上也沒(méi)有限制
返回狀態(tài)碼
100:請(qǐng)求者應(yīng)當(dāng)繼續(xù)提出請(qǐng)求镀首。服務(wù)器返回此代碼則意味著坟漱,服務(wù)器已收到了請(qǐng)求的第一部分,現(xiàn)正在等
待接收其余部分更哄。
101(切換協(xié)議)請(qǐng)求者已要求服務(wù)器切換協(xié)議芋齿,服務(wù)器已確認(rèn)并準(zhǔn)備進(jìn)行切換腥寇。
200:請(qǐng)求被正常處理
204:請(qǐng)求被受理但沒(méi)有資源可以返回
206:客戶(hù)端只是請(qǐng)求資源的一部分,服務(wù)器只對(duì)請(qǐng)求的部分資源執(zhí)行GET方法觅捆,相應(yīng)報(bào)文中通過(guò)Content-Range指定范圍的資源赦役。
301:永久性重定向
302:臨時(shí)重定向
303:與302狀態(tài)碼有相似功能,只是它希望客戶(hù)端在請(qǐng)求一個(gè)URI的時(shí)候栅炒,能通過(guò)GET方法重定向到另一個(gè)URI上
304:發(fā)送附帶條件的請(qǐng)求時(shí)掂摔,條件不滿(mǎn)足時(shí)返回,與重定向無(wú)關(guān)
307:臨時(shí)重定向赢赊,與302類(lèi)似乙漓,只是強(qiáng)制要求使用POST方法
400:請(qǐng)求報(bào)文語(yǔ)法有誤,服務(wù)器無(wú)法識(shí)別
401:請(qǐng)求需要認(rèn)證
403:請(qǐng)求的對(duì)應(yīng)資源禁止被訪問(wèn)
404:服務(wù)器無(wú)法找到對(duì)應(yīng)資源
500:服務(wù)器內(nèi)部錯(cuò)誤
503:服務(wù)器正忙
HTTP 協(xié)議頭相關(guān)
http數(shù)據(jù)由請(qǐng)求行释移,首部字段叭披,空行,報(bào)文主體四個(gè)部分組成
首部字段分為:通用首部字段玩讳,請(qǐng)求首部字段趋观,響應(yīng)首部字段,實(shí)體首部字段
https與http的區(qū)別锋边?如何實(shí)現(xiàn)加密傳輸?
- https就是在http與傳輸層之間加上了一個(gè)SSL
- 對(duì)稱(chēng)加密與非對(duì)稱(chēng)加密:非對(duì)稱(chēng)加密和解密使用的是兩個(gè)不同的密鑰编曼,公鑰和私鑰豆巨,不需要交換密鑰
瀏覽器中輸入一個(gè)URL發(fā)生什么,用到哪些協(xié)議掐场?
瀏覽器中輸入U(xiǎn)RL往扔,首先瀏覽器要將URL解析為IP地址,解析域名就要用到DNS協(xié)議熊户,首先主機(jī)會(huì)查詢(xún)DNS的緩存萍膛,如果沒(méi)有就給本地DNS發(fā)送查詢(xún)請(qǐng)求。DNS查詢(xún)分為兩種方式嚷堡,一種是遞歸查詢(xún)蝗罗,一種是迭代查詢(xún)。如果是迭代查詢(xún)蝌戒,本地的DNS服務(wù)器串塑,向根域名服務(wù)器發(fā)送查詢(xún)請(qǐng)求,根域名服務(wù)器告知該域名的一級(jí)域名服務(wù)器北苟,然后本地服務(wù)器給該一級(jí)域名服務(wù)器發(fā)送查詢(xún)請(qǐng)求桩匪,然后依次類(lèi)推直到查詢(xún)到該域名的IP地址。DNS服務(wù)器是基于UDP的友鼻,因此會(huì)用到UDP協(xié)議傻昙。
得到IP地址后闺骚,瀏覽器就要與服務(wù)器建立一個(gè)http連接。因此要用到http協(xié)議妆档,http協(xié)議報(bào)文格式上面已經(jīng)提到僻爽。http生成一個(gè)get請(qǐng)求報(bào)文,將該報(bào)文傳給TCP層處理过吻。如果采用https還會(huì)先對(duì)http數(shù)據(jù)進(jìn)行加密进泼。TCP層如果有需要先將HTTP數(shù)據(jù)包分片,分片依據(jù)路徑MTU和MSS纤虽。TCP的數(shù)據(jù)包然后會(huì)發(fā)送給IP層乳绕,用到IP協(xié)議。IP層通過(guò)路由選路逼纸,一跳一跳發(fā)送到目的地址洋措。當(dāng)然在一個(gè)網(wǎng)段內(nèi)的尋址是通過(guò)以太網(wǎng)協(xié)議實(shí)現(xiàn)(也可以是其他物理層協(xié)議,比如PPP杰刽,SLIP)菠发,以太網(wǎng)協(xié)議需要直到目的IP地址的物理地址,有需要ARP協(xié)議贺嫂。
數(shù)據(jù)庫(kù)
SQL語(yǔ)言(內(nèi)外連接滓鸠,子查詢(xún),分組第喳,聚集糜俗,嵌套,邏輯)
MySQL索引方法曲饱?索引的優(yōu)化悠抹?
InnoDB與MyISAM區(qū)別?
事務(wù)的ACID
事務(wù)的四個(gè)隔離級(jí)別
查詢(xún)優(yōu)化(從索引上優(yōu)化扩淀,從SQL語(yǔ)言上優(yōu)化)
B-與B+樹(shù)區(qū)別楔敌?
MySQL的聯(lián)合索引(又稱(chēng)多列索引)是什么?生效的條件驻谆?
分庫(kù)分表
Linux
進(jìn)程與線程
-
進(jìn)程與線程區(qū)別
- 進(jìn)程是資源分配的基本單位卵凑,線程是cpu調(diào)度,或者說(shuō)是程序執(zhí)行的最小單位胜臊。但是并不是說(shuō)CPU不在以進(jìn)程為單位進(jìn)行調(diào)度氛谜,雖然在某些操作系統(tǒng)中是這樣。同一個(gè)進(jìn)程中并行運(yùn)行多個(gè)線程区端,就是對(duì)在同一臺(tái)計(jì)算機(jī)上運(yùn)行多個(gè)進(jìn)程的模擬值漫。
- 進(jìn)程有獨(dú)立的地址空間,而同一進(jìn)程中的線程共享該進(jìn)程的地址空間织盼。比如在linux下面啟動(dòng)一個(gè)新的進(jìn)程杨何,系統(tǒng)必須分配給它獨(dú)立的地址空間酱塔,建立眾多的數(shù)據(jù)表來(lái)維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段危虱,這是一種非常昂貴的多任務(wù)工作方式羊娃。而運(yùn)行一個(gè)進(jìn)程中的線程,它們之間共享大部分?jǐn)?shù)據(jù)埃跷,使用相同的地址空間蕊玷,因此啟動(dòng)一個(gè)線程,切換一個(gè)線程遠(yuǎn)比進(jìn)程操作要快弥雹,花費(fèi)也要小得多垃帅。
- 線程之間的通信比較方便。統(tǒng)一進(jìn)程下的線程共享數(shù)據(jù)(比如全局變量剪勿,靜態(tài)變量贸诚,打開(kāi)的文件,子進(jìn)程)
- 多進(jìn)程比多線程程序要健壯厕吉。一個(gè)線程死掉整個(gè)進(jìn)程就死掉了酱固,但是在保護(hù)模式下,一個(gè)進(jìn)程死掉對(duì)另一個(gè)進(jìn)程沒(méi)有直接影響头朱。
- 線程的執(zhí)行與進(jìn)程是有區(qū)別的运悲。每個(gè)獨(dú)立的線程有有自己的一個(gè)程序入口,順序執(zhí)行序列和程序的出口项钮,但是線程不能獨(dú)立執(zhí)行班眯,必須依附與程序之中,由應(yīng)用程序提供多個(gè)線程的并發(fā)控制寄纵。
- linux中進(jìn)程具有父子關(guān)系,形成進(jìn)程樹(shù)脖苏,但是線程是平等的沒(méi)有父子關(guān)系
-
多線程VS多進(jìn)程程拭?
- 多進(jìn)程程序,一個(gè)進(jìn)程崩潰不會(huì)影響其他進(jìn)程棍潘,但是進(jìn)程之間的切換和通信代價(jià)較大恃鞋;
- 多線程程序,一個(gè)線程崩潰會(huì)導(dǎo)致整個(gè)進(jìn)程死掉亦歉,其他線程也不能正常工作恤浪,但是線程之前數(shù)據(jù)共享和通信更加方便。
- 進(jìn)程需要開(kāi)辟獨(dú)立的地址空間肴楷,多進(jìn)程對(duì)資源的消耗很大水由,而線程則是“輕量級(jí)進(jìn)程”,對(duì)資源的消耗更小赛蔫,對(duì)于大并發(fā)的情況砂客,只有線程加上IO復(fù)用技術(shù)才能適應(yīng)泥张。
因此,對(duì)于需要頻繁交互數(shù)據(jù)的鞠值,頻繁的對(duì)同一個(gè)對(duì)象進(jìn)行不同的處理媚创,選擇多線程合適,對(duì)于一些并發(fā)編程彤恶,不需要很多數(shù)據(jù)交互的采用多進(jìn)程钞钙。
-
用線程的好處
- 一個(gè)任務(wù)可以分成多個(gè)子任務(wù)并行執(zhí)行,他們是對(duì)一個(gè)對(duì)象在操作声离。
- 線程不需要像進(jìn)程一樣維護(hù)那么多信息芒炼,因此創(chuàng)建和銷(xiāo)毀速度更快,擁有同一個(gè)地址空間抵恋,訪問(wèn)很容易
- 任務(wù)有CPU密集和IO等待的過(guò)程焕议,使用線程可以最大化利用CPU
進(jìn)程的內(nèi)存空間布局
進(jìn)程的內(nèi)存布局在結(jié)構(gòu)上是有規(guī)律的,具體來(lái)說(shuō)對(duì)于linux系統(tǒng)上的進(jìn)程弧关,其內(nèi)存空間一般可以粗略地分為以下幾大段盅安,從高內(nèi)存到低內(nèi)存排列:
- 內(nèi)核態(tài)內(nèi)存空間,其大小一般比較固定(可以編譯時(shí)調(diào)整)世囊,但 32 位系統(tǒng)和 64 位系統(tǒng)的值不一樣别瞭。
- 用戶(hù)態(tài)的棧,大小不固定株憾,可以用 ulimit -s 進(jìn)行調(diào)整蝙寨,默認(rèn)一般為 8M,從高地址向低地址增長(zhǎng)嗤瞎。
- 共享內(nèi)存區(qū)墙歪,包括動(dòng)態(tài)共享庫(kù)以及mmap內(nèi)存映射的區(qū)域
- 堆,由程序員手動(dòng)分配
- 數(shù)據(jù)段贝奇,bss 未初始化 以及 data 已初始化的全局靜態(tài)變量等
- 代碼段虹菲,二進(jìn)制文件
[圖片上傳失敗...(image-42ade8-1525264842791)]
進(jìn)程間通信方式
信號(hào)量:信號(hào)量用于實(shí)現(xiàn)進(jìn)程間的互斥與同步,而不是用于存儲(chǔ)進(jìn)程間通信數(shù)據(jù)掉瞳。
管道( pipe ):管道是一種半雙工的通信方式毕源,數(shù)據(jù)只能單向流動(dòng),而且只能在具有親緣關(guān)系的進(jìn)程間使用陕习。進(jìn)程的親緣關(guān)系通常是指父子進(jìn)程關(guān)系霎褐。
命名管道 (named pipe) : 有名管道也是半雙工的通信方式,但是它允許無(wú)親緣關(guān)系進(jìn)程間的通信该镣。
消息隊(duì)列( message queue ) : 消息隊(duì)列是由消息的鏈表冻璃,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識(shí)符標(biāo)識(shí)。消息隊(duì)列克服了信號(hào)傳遞信息少、管道只能承載無(wú)格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)俱饿。
信號(hào) ( sinal ) : 信號(hào)是一種比較復(fù)雜的通信方式歌粥,用于通知接收進(jìn)程某個(gè)事件已經(jīng)發(fā)生。
共享內(nèi)存( shared memory ) :共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問(wèn)的內(nèi)存拍埠,這段共享內(nèi)存由一個(gè)進(jìn)程創(chuàng)建失驶,但多個(gè)進(jìn)程都可以訪問(wèn)。共享內(nèi)存是最快的 IPC 方式枣购,它是針對(duì)其他進(jìn)程間通信方式運(yùn)行效率低而專(zhuān)門(mén)設(shè)計(jì)的嬉探。它往往與其他通信機(jī)制,如信號(hào)兩棉圈,配合使用涩堤,來(lái)實(shí)現(xiàn)進(jìn)程間的同步和通信。
套接字( socket ) : 套解口也是一種進(jìn)程間通信機(jī)制分瘾,與其他通信機(jī)制不同的是胎围,它可用于不同及其間的進(jìn)程通信。
匿名管道與命名管道的區(qū)別:匿名管道只能在具有公共祖先的兩個(gè)進(jìn)程間使用
共享文件映射mmap
mmap建立進(jìn)程空間到文件的映射德召,在建立的時(shí)候并不直接將文件拷貝到物理內(nèi)存白魂,同樣采用缺頁(yè)終端。mmap映射一個(gè)具體的文件可以實(shí)現(xiàn)任意進(jìn)程間共享內(nèi)存上岗,映射一個(gè)匿名文件福荸,可以實(shí)現(xiàn)父子進(jìn)程間共享內(nèi)存。
常見(jiàn)信號(hào)
- SIGINT 終止進(jìn)程肴掷,通常我們的Ctrl+C就發(fā)送的這個(gè)消息敬锐。
- SIGKILL 消息編號(hào)為9,我們經(jīng)常用kill -9來(lái)殺死進(jìn)程發(fā)送的就是這個(gè)消息呆瞻,程序收到這個(gè)消息立即終止台夺,這個(gè)消息不能被捕獲,封鎖或這忽略痴脾,所以是殺死進(jìn)程的終極武器颤介。
- SIGTERM 是不帶參數(shù)時(shí)kill默認(rèn)發(fā)送的信號(hào),默認(rèn)是殺死進(jìn)程明郭。(可以被捕獲)
- SIGSEGV 就是SegmentFault 試圖訪問(wèn)未分配給自己的內(nèi)存, 或試圖往沒(méi)有寫(xiě)權(quán)限的內(nèi)存地址寫(xiě)數(shù)據(jù)
- SIGCHLD 一個(gè)子進(jìn)程停止或終止买窟,默認(rèn)行為忽略
- SIGALRM 來(lái)自alarm函數(shù)的定時(shí)信號(hào)丰泊,默認(rèn)行為 終止
內(nèi)存管理
虛擬內(nèi)存
操作系統(tǒng)對(duì)內(nèi)存的管理
幾種數(shù)據(jù)結(jié)構(gòu):
- 位圖
- 空閑塊鏈表
內(nèi)存分配算法:
- 首次適配first fit
- 下次適配next fit從上次找到的空閑區(qū)接著找
- 最佳適配best fit查找整個(gè)空閑區(qū)表薯定,能滿(mǎn)足要求的最小空閑區(qū)
- 最差適配worst fit總是分配最大空閑區(qū)
內(nèi)存池
內(nèi)存池的作用:
- 在C和C++語(yǔ)言中,經(jīng)常需要?jiǎng)討B(tài)分配內(nèi)存瞳购,我們會(huì)用到new话侄,delete,malloc,free年堆。但是當(dāng)我們分配很多小塊的內(nèi)存時(shí)吞杭,會(huì)造成很多的內(nèi)存碎片,大大降低了內(nèi)存的使用效率变丧。為了減少內(nèi)存碎片的出現(xiàn)芽狗,采用了內(nèi)存池技術(shù)。
內(nèi)存池的實(shí)現(xiàn)原理:
- 內(nèi)存池的先調(diào)用malloc函數(shù)申請(qǐng)一大塊內(nèi)存痒蓬,然后維護(hù)一個(gè)空閑鏈表童擎,該鏈表是一個(gè)個(gè)小的空閑內(nèi)存片,每當(dāng)需要內(nèi)存時(shí)就從空閑鏈表上拿過(guò)來(lái)一個(gè)小片內(nèi)存使用攻晒。如果空閑鏈表為空了顾复,就從之前分配的大塊內(nèi)存去取幾個(gè)插入到空閑鏈表上。如果分配的大塊內(nèi)存也用光了鲁捏,就繼續(xù)用malloc申請(qǐng)一大塊芯砸。
進(jìn)程空間和內(nèi)核空間對(duì)內(nèi)存的管理不同?
linux的slab層
slab是Linux操作系統(tǒng)的一種內(nèi)存分配機(jī)制给梅。其工作是針對(duì)一些經(jīng)常分配并釋放的對(duì)象假丧,如進(jìn)程描述符等,這些對(duì)象的大小一般比較小破喻,如果直接采用伙伴系統(tǒng)來(lái)進(jìn)行分配和釋放虎谢,不僅會(huì)造成大量的內(nèi)存碎片,而且處理速度也太慢曹质。而slab分配器是基于對(duì)象進(jìn)行管理的婴噩,相同類(lèi)型的對(duì)象歸為一類(lèi)(如進(jìn)程描述符就是一類(lèi)),每當(dāng)要申請(qǐng)這樣一個(gè)對(duì)象羽德,slab分配器就從一個(gè)slab列表中分配一個(gè)這樣大小的單元出去几莽,而當(dāng)要釋放時(shí),將其重新保存在該列表中宅静,而不是直接返回給伙伴系統(tǒng)章蚣,從而避免這些內(nèi)碎片。slab分配器并不丟棄已分配的對(duì)象姨夹,而是釋放并把它們保存在內(nèi)存中纤垂。當(dāng)以后又要請(qǐng)求新的對(duì)象時(shí),就可以從內(nèi)存直接獲取而不用重復(fù)初始化磷账。
伙伴算法
解決問(wèn)題:頻繁地請(qǐng)求和釋放不同大小的一組連續(xù)頁(yè)框峭沦,必然導(dǎo)致在已分配頁(yè)框的塊內(nèi)分散了許多小塊的空閑頁(yè)面,由此帶來(lái)的問(wèn)題是逃糟,即使有足夠的空閑頁(yè)框可以滿(mǎn)足請(qǐng)求吼鱼,但要分配一個(gè)大塊的連續(xù)頁(yè)框可能無(wú)法滿(mǎn)足請(qǐng)求蓬豁。
伴算法雖然能夠完全避免外部碎片的產(chǎn)生,但這恰恰是以產(chǎn)生內(nèi)部碎片為代價(jià)的菇肃。
優(yōu)點(diǎn):
- 較好解決外部碎片問(wèn)題
- 當(dāng)需要分配若干個(gè)內(nèi)存頁(yè)面時(shí)地粪,用于DMA的內(nèi)存頁(yè)面必須連續(xù),伙伴算法很好的滿(mǎn)足了這個(gè)要求
- 只要請(qǐng)求的塊不超過(guò)512個(gè)頁(yè)面(2K)琐谤,內(nèi)核就盡量分配連續(xù)的頁(yè)面蟆技。
- 針對(duì)大內(nèi)存分配設(shè)計(jì)。
缺點(diǎn):
- 合并的要求太過(guò)嚴(yán)格斗忌,只能是滿(mǎn)足伙伴關(guān)系的塊才能合并付魔,比如第1塊和第2塊就不能合并。
- 碎片問(wèn)題:一個(gè)連續(xù)的內(nèi)存中僅僅一個(gè)頁(yè)面被占用飞蹂,導(dǎo)致整塊內(nèi)存區(qū)都不具備合并的條件
- 浪費(fèi)問(wèn)題:伙伴算法只能分配2的冪次方內(nèi)存區(qū)几苍,當(dāng)需要8K(2頁(yè))時(shí),好說(shuō)陈哑,當(dāng)需要9K時(shí)妻坝,那就需要分配16K(4頁(yè))的內(nèi)存空間,但是實(shí)際只用到9K空間惊窖,多余的7K空間就被浪費(fèi)掉刽宪。
- 算法的效率問(wèn)題: 伙伴算法涉及了比較多的計(jì)算還有鏈表和位圖的操作,開(kāi)銷(xiāo)還是比較大的界酒,如果每次2n大小的伙伴塊就會(huì)合并到2(n+1)的鏈表隊(duì)列中圣拄,那么2n大小鏈表中的塊就會(huì)因?yàn)楹喜⒉僮鞫鴾p少,但系統(tǒng)隨后立即有可能又有對(duì)該大小塊的需求毁欣,為此必須再?gòu)?(n+1)大小的鏈表中拆分庇谆,這樣的合并又立即拆分的過(guò)程是無(wú)效率的。
所有的空閑頁(yè)框分組為 11 塊鏈表凭疮,每一塊鏈表分別包含大小為1饭耳,2,4执解,8寞肖,16,32衰腌,64新蟆,128,256右蕊,512 和 1024 個(gè)連續(xù)的頁(yè)框琼稻。
實(shí)現(xiàn)原理:
- 假設(shè)要請(qǐng)求一個(gè)256(129~256)個(gè)頁(yè)框的塊。算法先在256個(gè)頁(yè)框的鏈表中檢查是否有一個(gè)空閑塊尤泽。如果沒(méi)有這樣的塊欣簇,算法會(huì)查找下一個(gè)更大的頁(yè)塊,也就是坯约,在512個(gè)頁(yè)框的鏈表中找一個(gè)空閑塊。如果存在這樣的塊,內(nèi)核就把512的頁(yè)框分成兩等分谚咬,一般用作滿(mǎn)足需求赚导,另一半則插入到256個(gè)頁(yè)框的鏈表中。如果在512個(gè)頁(yè)框的塊鏈表中也沒(méi)找到空閑塊卿拴,就繼續(xù)找更大的塊——1024個(gè)頁(yè)框的塊衫仑。如果這樣的塊存在,內(nèi)核就把1024個(gè)頁(yè)框塊的256個(gè)頁(yè)框用作請(qǐng)求堕花,然后剩余的768個(gè)頁(yè)框中拿512個(gè)插入到512個(gè)頁(yè)框的鏈表中文狱,再把最后的256個(gè)插入到256個(gè)頁(yè)框的鏈表中。如果1024個(gè)頁(yè)框的鏈表還是空的缘挽,算法就放棄并發(fā)出錯(cuò)誤信號(hào)瞄崇。
高端內(nèi)存?
Linux是如何避免內(nèi)存碎片的
- 伙伴算法壕曼,用于管理物理內(nèi)存苏研,避免內(nèi)存碎片;
- 高速緩存Slab層用于管理內(nèi)核分配內(nèi)存,避免碎片腮郊。
共享內(nèi)存的實(shí)現(xiàn)原理摹蘑?
共享內(nèi)存實(shí)現(xiàn)分為兩種方式一種是采用mmap,另一種是采用XSI機(jī)制中的共享內(nèi)存方法轧飞。mmap是內(nèi)存文件映射衅鹿,將一個(gè)文件映射到進(jìn)程的地址空間,用戶(hù)進(jìn)程的地址空間的管理是通過(guò)vm_area_struct結(jié)構(gòu)體進(jìn)行管理的过咬。mmap通過(guò)映射一個(gè)相同的文件到兩個(gè)不同的進(jìn)程塘安,就能實(shí)現(xiàn)這兩個(gè)進(jìn)程的通信,采用該方法可以實(shí)現(xiàn)任意進(jìn)程之間的通信援奢。mmap也可以采用匿名映射兼犯,不指定映射的文件切黔,但是只能在父子進(jìn)程間通信。XSI的內(nèi)存共享實(shí)際上也是通過(guò)映射文件實(shí)現(xiàn)诗芜,只是其映射的是一種特殊文件系統(tǒng)下的文件孩哑,該文件是不能通過(guò)read和write訪問(wèn)的。
同步方法有哪些丛晌?
- 互斥鎖,自旋鎖瓶竭,信號(hào)量斤贰,讀寫(xiě)鎖荧恍,屏障
- 互斥鎖與自旋鎖的區(qū)別:互斥鎖得不到資源的時(shí)候阻塞送巡,不占用cpu資源骗爆。自旋鎖得不到資源的時(shí)候,不停的查詢(xún),而然占用cpu資源。
++i是否是原子操作
明顯不是宋光,++i主要有三個(gè)步驟逛漫,把數(shù)據(jù)從內(nèi)存放在寄存器上,在寄存器上進(jìn)行自增投储,把數(shù)據(jù)從寄存器拷貝會(huì)內(nèi)存第练,每個(gè)步驟都可能被中斷玛荞。
大小端
大端模式,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的低地址中勋眯,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的高地址中,這樣的存儲(chǔ)模式有點(diǎn)兒類(lèi)似于把數(shù)據(jù)當(dāng)作字符串順序處理:地址由小向大增加客蹋,而數(shù)據(jù)從高位往低位放塞蹭;這和我們的閱讀習(xí)慣一致讶坯。
小端模式番电,是指數(shù)據(jù)的高字節(jié)保存在內(nèi)存的高地址中娩井,而數(shù)據(jù)的低字節(jié)保存在內(nèi)存的低地址中洞辣,這種存儲(chǔ)模式將地址的高低和數(shù)據(jù)位權(quán)有效地結(jié)合起來(lái)屋彪,高地址部分權(quán)值高,低地址部分權(quán)值低绒尊。
判斷大小端
union un
{
int i;
char ch;
};
void fun()
{
union un test;
test.i = 1;
if(ch == 1)
cout << "小端" << endl;
else
cout << "大端" << endl;
}
如何判斷操作系統(tǒng)是32位還是64位畜挥?
- Linux指令uname
- 利用sizeof,判斷指針大小婴谱,或者其他變量蟹但,如long, unsigned long
- 機(jī)器位數(shù)不同躯泰,表示的數(shù)字最大值也不同
- 對(duì)0值取反,判斷是不是大于32位下所能表示的最大數(shù)
其他
設(shè)計(jì)模式
- 單例模式線程安全寫(xiě)法华糖,參考12. C++寫(xiě)一個(gè)線程安全的單例模式
- STL里的迭代器使用了迭代器模式
- MVC的理解
分布式系統(tǒng)
- mapreduce
- 負(fù)載均衡
- CDN