网易(杭州研究所)初面
覆蓋索引
如何實(shí)現(xiàn)索引覆蓋?
常見(jiàn)的方法是:將被查詢(xún)的字段,建立到聯(lián)合索引里去。
InnoDB聚集索引的葉子節(jié)點(diǎn)存儲(chǔ)行記錄,因此, InnoDB必須要有,且只有一個(gè)聚集索引
InnoDB普通索引的葉子節(jié)點(diǎn)存儲(chǔ)主鍵值。
舉個(gè)栗子,不妨設(shè)有表:
t(id PK, name KEY, sex, flag);
畫(huà)外音:id是聚集索引,name是普通索引。
表中有四條記錄:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
兩個(gè)B+樹(shù)索引分別如上圖:
(1)id為PK,聚集索引,葉子節(jié)點(diǎn)存儲(chǔ)行記錄;
(2)name為KEY,普通索引,葉子節(jié)點(diǎn)存儲(chǔ)PK值,即id;
既然從普通索引無(wú)法直接定位行記錄,那普通索引的查詢(xún)過(guò)程是怎么樣的呢?
通常情況下,需要掃描兩遍索引樹(shù)。
例如:
select * from t where name=‘lisi’;
是如何執(zhí)行的呢?
如粉紅色路徑,需要掃碼兩遍索引樹(shù):
(1)先通過(guò)普通索引定位到主鍵值id=5;
(2)在通過(guò)聚集索引定位到行記錄;
這就是所謂的回表查詢(xún),先定位主鍵值,再定位行記錄,它的性能較掃一遍索引樹(shù)更低。
當(dāng)發(fā)起一個(gè)被索引覆蓋的查詢(xún)(也叫作索引覆蓋查詢(xún))時(shí),在EXPLAIN的Extra列可以看到“Using index”的信息
不是所有類(lèi)型的索引都可以成為覆蓋索引。覆蓋索引必須要存儲(chǔ)索引的列,而哈希索引、空間索引和全文索引等都不存儲(chǔ)索引列的值,所以MySQL只能使用B-Tree索引做覆蓋索引
如何實(shí)現(xiàn)索引覆蓋?
select id,name,sex* from user where name=‘shenjian’;*
能夠命中name索引,索引葉子節(jié)點(diǎn)存儲(chǔ)了主鍵id,但sex字段必須回表查詢(xún)才能獲取到,不符合索引覆蓋,需要再次通過(guò)id值掃碼聚集索引獲取sex字段,效率會(huì)降低。
如果把(name)單列索引升級(jí)為聯(lián)合索引(name, sex)就不同了,可以避免回表。
參考:https://www.jianshu.com/p/8991cbca3854
ping實(shí)現(xiàn)以及對(duì)應(yīng)協(xié)議
ping是定位網(wǎng)絡(luò)通不通的一個(gè)重要手段,是用來(lái)探測(cè)本機(jī)與網(wǎng)絡(luò)中另一臺(tái)主機(jī)之間是否可達(dá)的命令,如果兩臺(tái)主機(jī)之間ping不通,則表明這兩臺(tái)主機(jī)不能建立起連接。
ping命令是基于ICMP協(xié)議來(lái)工作的,ping命令會(huì)發(fā)送一份ICMP回顯請(qǐng)求報(bào)文給目標(biāo)主機(jī),并等待目標(biāo)主機(jī)返回ICMP回顯應(yīng)達(dá),如果源主機(jī)在一定時(shí)間內(nèi)收到了目標(biāo)主機(jī)的應(yīng)答,則表明兩臺(tái)主機(jī)間是連通的。
舉一個(gè)例子來(lái)描述ping命令工作的原理
1)假設(shè)有兩個(gè)主機(jī),主機(jī)A(192.168.0.1)和主機(jī)B(192.168.0.2),現(xiàn)在我們要監(jiān)測(cè)主機(jī)A和主機(jī)B之間網(wǎng)絡(luò)是否可達(dá),那么我們?cè)谥鳈C(jī)A上輸入命令:ping 192.168.0.2;
2)此時(shí),ping命令會(huì)在主機(jī)A上構(gòu)建一個(gè) ICMP的請(qǐng)求數(shù)據(jù)包,然后 ICMP協(xié)議會(huì)將這個(gè)數(shù)據(jù)包以及目標(biāo)IP(192.168.0.2)等信息一同交給IP層協(xié)議;
3)IP層協(xié)議得到這些信息后,將源地址(即本機(jī)IP)、目標(biāo)地址(即目標(biāo)IP:192.168.0.2)、再加上一些其它的控制信息,構(gòu)建成一個(gè)IP數(shù)據(jù)包;
4)IP數(shù)據(jù)包構(gòu)建完成后,還不夠,還需要加上MAC地址,因此,還需要通過(guò)ARP映射表找出目標(biāo)IP所對(duì)應(yīng)的MAC地址。當(dāng)拿到了目標(biāo)主機(jī)的MAC地址和本機(jī)MAC后,一并交給數(shù)據(jù)鏈路層,組裝成一個(gè)數(shù)據(jù)幀,依據(jù)以太網(wǎng)的介質(zhì)訪問(wèn)規(guī)則,將它們傳送出出去;
5)當(dāng)主機(jī)B收到這個(gè)數(shù)據(jù)幀之后,會(huì)首先檢查它的目標(biāo)MAC地址是不是本機(jī),如果是就接收下來(lái)處理,接收之后會(huì)檢查這個(gè)數(shù)據(jù)幀,將數(shù)據(jù)幀中的IP數(shù)據(jù)包取出來(lái),交給本機(jī)的IP層協(xié)議,然后IP層協(xié)議檢查完之后,再將ICMP數(shù)據(jù)包取出來(lái)交給ICMP協(xié)議處理,當(dāng)這一步也處理完成之后,就會(huì)構(gòu)建一個(gè)ICMP應(yīng)答數(shù)據(jù)包,回發(fā)給主機(jī)A;
6)在一定的時(shí)間內(nèi),如果主機(jī)A收到了應(yīng)答包,則說(shuō)明它與主機(jī)B之間網(wǎng)絡(luò)可達(dá),如果沒(méi)有收到,則說(shuō)明網(wǎng)絡(luò)不可達(dá)。除了監(jiān)測(cè)是否可達(dá)以外,還可以利用應(yīng)答時(shí)間和發(fā)起時(shí)間之間的差值,計(jì)算出數(shù)據(jù)包的延遲耗時(shí)。
參考:https://www.cnblogs.com/mgd666/p/14389922.html
為什么要有Time-wait狀態(tài)(2MSL)
主動(dòng)關(guān)閉的Socket端會(huì)進(jìn)入TIME_WAIT狀態(tài),并且持報(bào)文段最大生存時(shí)間續(xù)2MSL時(shí)間長(zhǎng)度,MSL就是maximum segment lifetime(最大分節(jié)生命期),這是一個(gè)IP數(shù)據(jù)包能在互聯(lián)網(wǎng)上生存的最長(zhǎng)時(shí)間,超過(guò)這個(gè)時(shí)間將在網(wǎng)絡(luò)中消失。MSL在RFC 1122上建議是2分鐘,而源自berkeley的TCP實(shí)現(xiàn)傳統(tǒng)上使用30秒,因而,TIME_WAIT狀態(tài)一般維持在1-4分鐘。
TIME_WAIT狀態(tài)存在的理由:
1)可靠地實(shí)現(xiàn)TCP全雙工連接的終止
在進(jìn)行關(guān)閉連接四路握手協(xié)議時(shí),最后的ACK是由主動(dòng)關(guān)閉端發(fā)出的,如果這個(gè)最終的ACK丟失,服務(wù)器將重發(fā)最終的FIN,因此客戶(hù)端必須維護(hù)狀態(tài)信息允許它重發(fā)最終的ACK。如果不維持這個(gè)狀態(tài)信息,那么客戶(hù)端將響應(yīng)RST分節(jié),服務(wù)器將此分節(jié)解釋成一個(gè)錯(cuò)誤(在java中會(huì)拋出connection reset的SocketException)。因而,要實(shí)現(xiàn)TCP全雙工連接的正常終止,必須處理終止序列四個(gè)分節(jié)中任何一個(gè)分節(jié)的丟失情況,主動(dòng)關(guān)閉 的客戶(hù)端必須維持狀態(tài)信息進(jìn)入TIME_WAIT狀態(tài)。
2)允許老的重復(fù)分節(jié)在網(wǎng)絡(luò)中消逝
TCP分節(jié)可能由于路由器異常而“迷途”,在迷途期間,TCP發(fā)送端可能因確認(rèn)超時(shí)而重發(fā)這個(gè)分節(jié),迷途的分節(jié)在路由器修復(fù)后也會(huì)被送到最終目的地,這個(gè) 原來(lái)的迷途分節(jié)就稱(chēng)為lost duplicate。在關(guān)閉一個(gè)TCP連接后,馬上又重新建立起一個(gè)相同的IP地址和端口之間的TCP連接,后一個(gè)連接被稱(chēng)為前一個(gè)連接的化身(incarnation),那么有可能出現(xiàn)這種情況,前一個(gè)連接的迷途重復(fù)分組在前一個(gè)連接終止后出現(xiàn),從而被誤解成從屬于新的化身。為了避免這個(gè)情況,TCP不允許處于TIME_WAIT狀態(tài)的連接啟動(dòng)一個(gè)新的化身,因?yàn)門(mén)IME_WAIT狀態(tài)持續(xù)2MSL,就可以保證當(dāng)成功建立一個(gè)TCP連接的時(shí)候,來(lái)自連接先前化身的重復(fù)分組已經(jīng)在網(wǎng)絡(luò)中消逝。
參考:https://blog.csdn.net/tennysonsky/article/details/48680197
TIMESTAMP和DATETIME的區(qū)別以及選擇
補(bǔ)充:什么是UTC?
答:協(xié)調(diào)世界時(shí),又稱(chēng)世界統(tǒng)一時(shí)間,世界標(biāo)準(zhǔn)時(shí)間,國(guó)際協(xié)調(diào)時(shí)間,簡(jiǎn)稱(chēng)UTC
不屬于任意時(shí)區(qū)
中國(guó)大陸、中國(guó)香港、中國(guó)澳門(mén)、中國(guó)臺(tái)灣、蒙古國(guó)、新加坡、馬來(lái)西亞、菲律賓、西澳大利亞州的時(shí)間與UTC的時(shí)差均為+8,也就是UTC+8。
時(shí)區(qū)(Time Zone)是地球上的區(qū)域使用同一個(gè)時(shí)間定義。1884年在華盛頓召開(kāi)國(guó)際經(jīng)度會(huì)議時(shí),為了克服時(shí)間上的混亂,規(guī)定將全球劃分為24個(gè)時(shí)區(qū)。在中國(guó)采用首都北京所在地東八區(qū)的時(shí)間為全國(guó)統(tǒng)一使用時(shí)間。
對(duì)于MySQL中timestamp數(shù)據(jù)類(lèi)型的特點(diǎn),為什么選擇timestamp類(lèi)型?
答:int類(lèi)型占用4字節(jié),datetime占用8字節(jié),timestamp占用4字節(jié);通常情況下在選擇表中列的數(shù)據(jù)類(lèi)型時(shí)我們要選擇能滿足存儲(chǔ)需要的,最小的數(shù)據(jù)類(lèi)型,在使用MySQL數(shù)據(jù)庫(kù)時(shí)有很多常見(jiàn)的誤解,其中使用int類(lèi)型來(lái)保存日期數(shù)據(jù)會(huì)提高數(shù)據(jù)讀取的效率就是比較常見(jiàn)的一個(gè)誤解。顯然INT要比datetime類(lèi)型小很多,同時(shí)MySQL又提供了兩個(gè)非常好用的函數(shù)FROM_UNIXTIME() 和UNIX_TIMESTAMP(),使用這兩個(gè)函數(shù)可以方便的在INT和DATETIME類(lèi)型之間進(jìn)行轉(zhuǎn)換,但是使用INT類(lèi)型存儲(chǔ)時(shí)間也給我們帶來(lái)了不少的麻煩:
1.數(shù)據(jù)的可讀性比較差,我們?cè)诓榭磾?shù)據(jù)時(shí)不能直觀的看出時(shí)間列中記錄的一串整數(shù)所代表的時(shí)間
2.每次進(jìn)行顯示時(shí)都要通過(guò)函數(shù)進(jìn)行轉(zhuǎn)換,增加了數(shù)據(jù)使用的復(fù)雜成度。
那有沒(méi)有什么更好的方法來(lái)存儲(chǔ)日期數(shù)據(jù)呢?這就要用到我們標(biāo)題中所說(shuō)到的timestamp類(lèi)型了,timestamp類(lèi)型的特點(diǎn)如下:
1.存儲(chǔ)占用 4個(gè)字節(jié),以年月日小時(shí)分秒的日期型式顯示
2.存儲(chǔ)范圍’1970-01-01 00:00:01’ to ‘2038-01-19 03:14:07’.
3.以UTC時(shí)區(qū)進(jìn)行存儲(chǔ),但是以系統(tǒng)當(dāng)前時(shí)間進(jìn)行顯示
4.可以在insert和update時(shí)把值自動(dòng)更新為當(dāng)前時(shí)間
由以上特點(diǎn)可以知道,timestamp存儲(chǔ)占用的空間和INT類(lèi)型相同,實(shí)際上timestamp類(lèi)型的數(shù)據(jù)在存儲(chǔ)時(shí)就是被保存成INT類(lèi)型的數(shù)據(jù)來(lái)存儲(chǔ)的,這和我們使用INT來(lái)存儲(chǔ)日期時(shí)間數(shù)據(jù)可以說(shuō)是完全一樣的。由于同樣是使用INT類(lèi)型來(lái)保存數(shù)據(jù),所以和INT類(lèi)型一樣其存儲(chǔ)的時(shí)間范圍也是有限制的,
**這一點(diǎn)大家一定要注意,超過(guò)了這個(gè)范圍的日期數(shù)據(jù)建議大家使用datetime類(lèi)型來(lái)保存。**另外timestamp數(shù)據(jù)存儲(chǔ)時(shí)是以UTC時(shí)區(qū)來(lái)保存的,在顯示時(shí)MySQL會(huì)自動(dòng)的把數(shù)據(jù)轉(zhuǎn)換為當(dāng)前連接所對(duì)應(yīng)時(shí)間來(lái)顯示。
可見(jiàn),使用timestamp來(lái)存儲(chǔ)日期時(shí)間數(shù)據(jù)不但保證了數(shù)據(jù)類(lèi)型的大小同INT類(lèi)型一樣,同時(shí)可以顯示為日期時(shí)間格式,這在給我們使用數(shù)據(jù)帶來(lái)了很多的方便。所以強(qiáng)烈建議大家,使用timestamp類(lèi)型來(lái)存儲(chǔ)日期數(shù)據(jù)而不要再使用INT類(lèi)型了。(轉(zhuǎn)自:https://www.imooc.com/article/16158)
四次揮手相對(duì)三次握手多一次?
因?yàn)?#xff1a;客戶(hù)端單方面無(wú)數(shù)據(jù)發(fā)送認(rèn)為可以結(jié)束了,但是服務(wù)端不一定沒(méi)有數(shù)據(jù)發(fā)送,所以服務(wù)端要將確信信息和自身發(fā)起斷開(kāi)分作兩步
有了 IP 地址,為什么還要用 MAC 地址?
有了 IP 地址,為什么還要用 MAC 地址?
是TCP/IP協(xié)議的一部分。利用“ping”命令可以檢查網(wǎng)絡(luò)是否通暢或者網(wǎng)絡(luò)連接速度,很好地分析和判定網(wǎng)絡(luò)故障。
Ping發(fā)送一個(gè)ICMP(Internet Control Messages Protocol),即因特網(wǎng)信報(bào)控制協(xié)議;接收端回聲消息給目的地并報(bào)告是否收到所希望的ICMPecho (ICMP回聲應(yīng)答)。它的原理是:利用網(wǎng)絡(luò)上機(jī)器IP地址的唯一性,給目標(biāo)IP地址發(fā)送一個(gè)數(shù)據(jù)包,通過(guò)對(duì)方回復(fù)的數(shù)據(jù)包來(lái)確定兩臺(tái)網(wǎng)絡(luò)機(jī)器是否連接相通,時(shí)延是多少。
進(jìn)程間的通信
管道pipe:管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動(dòng),而且只能在具有親緣關(guān)系的進(jìn)程間使用。進(jìn)程的親緣關(guān)系通常是指父子進(jìn)程關(guān)系。
命名管道FIFO:有名管道也是半雙工的通信方式,但是它允許無(wú)親緣關(guān)系進(jìn)程間的通信。
消息隊(duì)列MessageQueue:消息隊(duì)列是由消息的鏈表,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識(shí)符標(biāo)識(shí)。消息隊(duì)列克服了信號(hào)傳遞信息少、管道只能承載無(wú)格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。
共享存儲(chǔ)SharedMemory:共享內(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)程間的同步和通信。
信號(hào)量Semaphore:信號(hào)量是一個(gè)計(jì)數(shù)器,可以用來(lái)控制多個(gè)進(jìn)程對(duì)共享資源的訪問(wèn)。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問(wèn)共享資源時(shí),其他進(jìn)程也訪問(wèn)該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
套接字Socket:套解口也是一種進(jìn)程間通信機(jī)制,與其他通信機(jī)制不同的是,它可用于不同及其間的進(jìn)程通信。
信號(hào) ( sinal ) : 信號(hào)是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個(gè)事件已經(jīng)發(fā)生。
補(bǔ)充:線程間的通信方式
鎖機(jī)制:包括互斥鎖、條件變量、讀寫(xiě)鎖
互斥鎖提供了以排他方式防止數(shù)據(jù)結(jié)構(gòu)被并發(fā)修改的方法。
讀寫(xiě)鎖允許多個(gè)線程同時(shí)讀共享數(shù)據(jù),而對(duì)寫(xiě)操作是互斥的。
條件變量可以以原子的方式阻塞進(jìn)程,直到某個(gè)特定條件為真為止。對(duì)條件的測(cè)試是在互斥鎖的保護(hù)下進(jìn)行的。條件變量始終與互斥鎖一起使用。
信號(hào)量機(jī)制(Semaphore):包括無(wú)名線程信號(hào)量和命名線程信號(hào)量
信號(hào)機(jī)制(Signal):類(lèi)似進(jìn)程間的信號(hào)處理
線程間的通信目的主要是用于線程同步,所以線程沒(méi)有像進(jìn)程通信中的用于數(shù)據(jù)交換的通信機(jī)制。
原文鏈接:https://blog.csdn.net/weixin_41903587/article/details/109529691
補(bǔ)充:堆和棧的區(qū)別
1.管理方式不同。棧由操作系統(tǒng)自動(dòng)分配釋放,不需要我們手動(dòng)控制;堆的申請(qǐng)和釋放工作由程序員控制,因此容易產(chǎn)生內(nèi)存泄漏。
2.空間大小不同。棧的大小一般只有8~10M,而堆有幾個(gè)G。
3.生長(zhǎng)方向不同。棧的生長(zhǎng)方向向下,內(nèi)存的地址由高到低,堆的生長(zhǎng)方向向上,內(nèi)存的地址由低到高。
4.分配方式不同。堆時(shí)動(dòng)態(tài)分配的;棧有兩種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是由操作系統(tǒng)完成,比如局部變量的分配。動(dòng)態(tài)分配由malloc函數(shù)進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的,棧的動(dòng)態(tài)分配是由操作系統(tǒng)進(jìn)行釋放,不需要我們手動(dòng)釋放。
5.分配效率不同。棧由操作系統(tǒng)自動(dòng)分配,會(huì)在硬件層級(jí)對(duì)棧提供支持。分配專(zhuān)門(mén)的寄存器存放棧的地址,壓棧出棧都有專(zhuān)門(mén)的指令執(zhí)行,這就決定了棧的效率比較高。堆則是由C/C++提供的庫(kù)函數(shù)或運(yùn)算符來(lái)完成申請(qǐng)與管理,實(shí)現(xiàn)機(jī)制比較復(fù)雜,頻繁的內(nèi)存申請(qǐng)容易產(chǎn)生內(nèi)存碎片。顯然,堆的效率比棧低得多。
由此可見(jiàn),堆和棧相比,由于大量malloc()/free()或new/delete的使用,容易造成大量的內(nèi)存碎片。棧相比于堆,在程序中應(yīng)用較為廣泛,最常見(jiàn)的函數(shù)調(diào)用過(guò)程由棧來(lái)實(shí)現(xiàn),函數(shù)返回地址、實(shí)參和局部變量都采用棧的方式存放。雖然棧有眾多的好處,但是和堆相比不是那么靈活,有時(shí)候分配大量的內(nèi)存空間任然需要用堆。總之無(wú)論是堆還是棧,在內(nèi)存使用時(shí)都要防止非法越界。
參考:https://blog.csdn.net/tangya3158613488/article/details/88845180
線程并行理解
用多線程只有一個(gè)目的,那就是更好的利用cpu的資源,因?yàn)樗械亩嗑€程代碼都可以用單線程來(lái)實(shí)現(xiàn)。說(shuō)這個(gè)話其實(shí)只有一半對(duì),因?yàn)榉磻?yīng)“多角色”的程序代碼,最起碼每個(gè)角色要給他一個(gè)線程吧,否則連實(shí)際場(chǎng)景都無(wú)法模擬,當(dāng)然也沒(méi)法說(shuō)能用單線程來(lái)實(shí)現(xiàn):比如最常見(jiàn)的“生產(chǎn)者,消費(fèi)者模型”。
很多人都對(duì)其中的一些概念不夠明確,如同步、并發(fā)等等,讓我們先建立一個(gè)數(shù)據(jù)字典,以免產(chǎn)生誤會(huì)。
多線程:指的是這個(gè)程序(一個(gè)進(jìn)程)運(yùn)行時(shí)產(chǎn)生了不止一個(gè)線程
并行與并發(fā):
并行:多個(gè)cpu實(shí)例或者多臺(tái)機(jī)器同時(shí)執(zhí)行一段處理邏輯,是真正的同時(shí)。
并發(fā):通過(guò)cpu調(diào)度算法,讓用戶(hù)看上去同時(shí)執(zhí)行,實(shí)際上從cpu操作層面不是真正的同時(shí)。并發(fā)往往在場(chǎng)景中有公用的資源,那么針對(duì)這個(gè)公用的資源往往產(chǎn)生瓶頸,我們會(huì)用TPS或者QPS來(lái)反應(yīng)這個(gè)系統(tǒng)的處理能力。
并發(fā)與并行
線程安全:經(jīng)常用來(lái)描繪一段代碼。指在并發(fā)的情況之下,該代碼經(jīng)過(guò)多線程使用,線程的調(diào)度順序不影響任何結(jié)果。這個(gè)時(shí)候使用多線程,我們只需要關(guān)注系統(tǒng)的內(nèi)存,cpu是不是夠用即可。
同步:Java中的同步指的是通過(guò)人為的控制和調(diào)度,保證共享資源的多線程訪問(wèn)成為線程安全,來(lái)保證結(jié)果的準(zhǔn)確。如上面的代碼簡(jiǎn)單加入@synchronized關(guān)鍵字。在保證結(jié)果準(zhǔn)確的同時(shí),提高性能,才是優(yōu)秀的程序。線程安全的優(yōu)先級(jí)高于性能。
多態(tài)
面向?qū)ο缶幊逃腥筇匦?#xff1a;封裝、繼承、多態(tài)。封裝隱藏了類(lèi)的內(nèi)部實(shí)現(xiàn)機(jī)制,可以在不影響使用的情況下改變類(lèi)的內(nèi)部結(jié)構(gòu),同時(shí)也保護(hù)了數(shù)據(jù)。對(duì)外界而已它的內(nèi)部細(xì)節(jié)是隱藏的,暴露給外界的只是它的訪問(wèn)方法。
繼承是為了重用父類(lèi)代碼。兩個(gè)類(lèi)若存在IS-A的關(guān)系就可以使用繼承。,同時(shí)繼承也為實(shí)現(xiàn)多態(tài)做了鋪墊。那么什么是多態(tài)呢?多態(tài)的實(shí)現(xiàn)機(jī)制又是什么?請(qǐng)看我一一為你揭開(kāi):
所謂多態(tài)就是指程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類(lèi)的實(shí)例對(duì)象,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類(lèi)中實(shí)現(xiàn)的方法,必須在由程序運(yùn)行期間才能決定。因?yàn)樵诔绦蜻\(yùn)行時(shí)才確定具體的類(lèi),這樣,不用修改源程序代碼,就可以讓引用變量綁定到各種不同的類(lèi)實(shí)現(xiàn)上,從而導(dǎo)致該引用調(diào)用的具體方法隨之改變,即不修改程序代碼就可以改變程序運(yùn)行時(shí)所綁定的具體代碼,讓程序可以選擇多個(gè)運(yùn)行狀態(tài),這就是多態(tài)性。
程序中定義的引用變量所指向的具體類(lèi)型和通過(guò)該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定,而是在程序運(yùn)行期間才確定
基本數(shù)據(jù)類(lèi)型和應(yīng)用數(shù)據(jù)類(lèi)型
Java中的數(shù)據(jù)類(lèi)型分為兩大類(lèi),基本數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型。
1、基本數(shù)據(jù)類(lèi)型
基本數(shù)據(jù)類(lèi)型只有8種,可按照如下分類(lèi)
①整數(shù)類(lèi)型:long、int、short、byte
②浮點(diǎn)類(lèi)型:float、double
③字符類(lèi)型:char
④布爾類(lèi)型:boolean
2、引用數(shù)據(jù)類(lèi)型
引用數(shù)據(jù)類(lèi)型非常多,大致包括:
類(lèi)、 接口類(lèi)型、 數(shù)組類(lèi)型、 枚舉類(lèi)型、 注解類(lèi)型、 字符串型
例如,String類(lèi)型就是引用類(lèi)型。
簡(jiǎn)單來(lái)說(shuō),所有的非基本數(shù)據(jù)類(lèi)型都是引用數(shù)據(jù)類(lèi)型。
二、基本數(shù)據(jù)類(lèi)型和引用數(shù)據(jù)類(lèi)型的區(qū)別
1、存儲(chǔ)位置
基本變量類(lèi)型
在方法中定義的非全局基本數(shù)據(jù)類(lèi)型變量的具體內(nèi)容是存儲(chǔ)在棧中的
引用變量類(lèi)型
只要是引用數(shù)據(jù)類(lèi)型變量,其具體內(nèi)容都是存放在堆中的,而棧中存放的是其具體內(nèi)容所在內(nèi)存的地址
ps:通過(guò)變量地址可以找到變量的具體內(nèi)容,就如同通過(guò)房間號(hào)可以找到房間一般
2、傳遞方式
基本變量類(lèi)型
在方法中定義的非全局基本數(shù)據(jù)類(lèi)型變量,調(diào)用方法時(shí)作為參數(shù)是按數(shù)值傳遞的
引用變量類(lèi)型
引用數(shù)據(jù)類(lèi)型變量,調(diào)用方法時(shí)作為參數(shù)是按引用傳遞的,傳遞的是引用的副本
調(diào)用時(shí)為temp在棧中開(kāi)辟新空間,并指向book的具體內(nèi)容,方法執(zhí)行完畢后temp在棧中的內(nèi)存被釋放掉
參考:https://www.cnblogs.com/maskwolf/p/9972982.html
Java垃圾回收機(jī)制
為什么要進(jìn)行垃圾回收?
隨著程序的運(yùn)行,內(nèi)存中存在的實(shí)例對(duì)象、變量等信息占據(jù)的內(nèi)存越來(lái)越多,如果不及時(shí)進(jìn)行垃圾回收,必然會(huì)帶來(lái)程序性能的下降,甚至?xí)驗(yàn)榭捎脙?nèi)存不足造成一些不必要的系統(tǒng)異常。
哪些“垃圾”需要回收?
如果某個(gè)對(duì)象已經(jīng)不存在任何引用,那么它可以被回收。
什么時(shí)候進(jìn)行垃圾回收?
引用計(jì)數(shù)算法
每個(gè)對(duì)象添加一個(gè)引用計(jì)數(shù)器,每被引用一次,計(jì)數(shù)器加1,失去引用,計(jì)數(shù)器減1,當(dāng)計(jì)數(shù)器在一段時(shí)間內(nèi)保持為0時(shí),該對(duì)象就認(rèn)為是可以被回收得了。(在JDK1.2之前,使用的是該算法)
缺點(diǎn):當(dāng)兩個(gè)對(duì)象A、B相互引用的時(shí)候,當(dāng)其他所有的引用都消失之后,A和B還有一個(gè)相互引用,此時(shí)計(jì)數(shù)器各為1,而實(shí)際上這兩個(gè)對(duì)象都已經(jīng)沒(méi)有額外的引用了,已經(jīng)是垃圾了。但是卻不會(huì)被回收
可達(dá)性分析算法
該算法是從離散數(shù)學(xué)中的圖論引入的,程序把所有的引用關(guān)系看作一張圖,從一個(gè)節(jié)點(diǎn)GC ROOT 開(kāi)始,尋找對(duì)應(yīng)的引用節(jié)點(diǎn),找到這個(gè)節(jié)點(diǎn)以后,繼續(xù)尋找這個(gè)節(jié)點(diǎn)的引用節(jié)點(diǎn),當(dāng)所有的引用節(jié)點(diǎn)尋找完畢之后,剩余的節(jié)點(diǎn)則被認(rèn)為是沒(méi)有被引用到的節(jié)點(diǎn),即無(wú)用的節(jié)點(diǎn)
目前java 中可作為GC Root 的對(duì)象有:
虛擬機(jī)棧中引用的對(duì)象(本地變量表)
方法區(qū)中靜態(tài)屬性引用的對(duì)象
方法區(qū)中常量引用的對(duì)象
本地方法棧中引用的對(duì)象(Native Object)
引用計(jì)數(shù)法
給對(duì)象添加一引用計(jì)數(shù)器,被引用一次計(jì)數(shù)器值就加 1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減 1;計(jì)數(shù)器為 0 時(shí),對(duì)象就是不可能再被使用的,簡(jiǎn)單高效,缺點(diǎn)是無(wú)法解決對(duì)象之間相互循環(huán)引用的問(wèn)題。
可達(dá)性分析算法
通過(guò)一系列的稱(chēng)為 “GC Roots” 的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱(chēng)為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到 GC Roots 沒(méi)有任何引用鏈相連時(shí),則證明此對(duì)象是不可用的。此算法解決了上述循環(huán)引用的問(wèn)題。
引用的分類(lèi)
JDK 1.2之后,對(duì)引用進(jìn)行了擴(kuò)充,引入了強(qiáng)、軟、若、虛四種引用,被標(biāo)記為這四種引用的對(duì)象,在GC時(shí)分別有不同的意義:
強(qiáng)引用(Strong Reference)
就是為剛被new出來(lái)的對(duì)象所加的引用,它的特點(diǎn)就是,永遠(yuǎn)不會(huì)被GC,除非顯示的設(shè)置null,才會(huì)GC。代碼如下:
Object ojb = new Object();
軟引用(Soft Reference)
非必須引用,內(nèi)存溢出之前進(jìn)行回收。如果JVM內(nèi)存并不緊張,這類(lèi)對(duì)象可以不被回收,如果內(nèi)存緊張,則會(huì)被回收。此處有一個(gè)問(wèn)題,既然被引用為軟引用的對(duì)象可以回收,為什么不去回收呢?其實(shí)我們知道,Java中是存在緩存機(jī)制的,就拿字面量緩存來(lái)說(shuō),有些時(shí)候,緩存的對(duì)象就是當(dāng)前可有可無(wú)的,只是留在內(nèi)存中如果還有需要,則不需要重新分配內(nèi)存即可使用,因此,這些對(duì)象即可被引用為軟引用,方便使用,提高程序性能。代碼如下:
Object obj = new Object();
SoftReference sf = new SoftReference(obj);
obj =null;
sf.get();//有時(shí)候會(huì)返回null
這時(shí)候sf是對(duì)obj的一個(gè)軟引用,通過(guò)sf.get()方法可以取到這個(gè)對(duì)象,當(dāng)然,當(dāng)這個(gè)對(duì)象被標(biāo)記為需要回收的對(duì)象時(shí),則返回null;
弱引用(Weak Reference)
第二次垃圾回收時(shí)回收。代碼如下:
Object obj = new Object();
WeakReference wf = new WeakReference(obj);
obj =null;
wf.get();//有時(shí)候會(huì)返回null
wf.isEnQueued();//返回是否被垃圾回收器標(biāo)記為即將回收的垃圾
弱引用是在第二次垃圾回收時(shí)回收,短時(shí)間內(nèi)通過(guò)弱引用取對(duì)應(yīng)的數(shù)據(jù),可以取到,當(dāng)執(zhí)行過(guò)第二次垃圾回收時(shí),將返回null。
弱引用主要用于監(jiān)控對(duì)象是否已經(jīng)被垃圾回收器標(biāo)記為即將回收的垃圾,可以通過(guò)弱引用的isEnQueued方法返回對(duì)象是否被垃圾回收器
虛引用(Phantom Reference)
垃圾回收時(shí)回收,無(wú)法通過(guò)引用取到對(duì)象值。代碼如下
Object obj = new Object();
PhantomReference pf = new PhantomReference(obj);
obj=null;
pf.get();//永遠(yuǎn)返回null
pf.isEnQueued();//返回從內(nèi)存中已經(jīng)刪除
虛引用是每次垃圾回收的時(shí)候都會(huì)被回收,通過(guò)虛引用的get方法永遠(yuǎn)獲取到的數(shù)據(jù)為null,因此也被成為幽靈引用。虛引用主要用于檢測(cè)對(duì)象是否已經(jīng)從內(nèi)存中刪除。
擴(kuò)展:如果一個(gè)對(duì)象的引用有多個(gè),怎么通過(guò)可達(dá)性確定回收周期呢?兩個(gè)原則:
單條引用鏈上,由最弱的一個(gè)引用類(lèi)型決定
多條引用鏈上,由最強(qiáng)的一個(gè)引用類(lèi)型決定
這個(gè)想想其實(shí)還是很好理解的。
原文鏈接:https://blog.csdn.net/w372426096/article/details/81360083
如何垃圾回收
內(nèi)存主要被分為三塊,新生代、舊生代、持久代。三代的特點(diǎn)不同,造就了他們所用的GC算法不同,新生代適合那些生命周期較短,頻繁創(chuàng)建及銷(xiāo)毀的對(duì)象,舊生代適合生命周期相對(duì)較長(zhǎng)的對(duì)象,持久代在Sun HotSpot中就是指方法區(qū)(有些JVM中根本就沒(méi)有持久代這中說(shuō)法)。首先介紹下新生代、舊生代、持久代的概念及特點(diǎn):
新生代:New Generation或者Young Generation。上面大致分為Eden區(qū)和Survivor區(qū),Survivor區(qū)又分為大小相同的兩部分:FromSpace 和ToSpace。新建的對(duì)象都是用新生代分配內(nèi)存,Eden空間不足的時(shí)候,會(huì)把存活的對(duì)象轉(zhuǎn)移到Survivor中,新生代的大小可以由-Xmn來(lái)控制,也可以用-XX:SurvivorRatio來(lái)控制Eden和Survivor的比例.
舊生代:Old Generation。用于存放新生代中經(jīng)過(guò)多次垃圾回收仍然存活的對(duì)象,例如緩存對(duì)象。舊生代占用大小為-Xmx值減去-Xmn對(duì)應(yīng)的值。
持久代:Permanent Generation。在Sun的JVM中就是方法區(qū)的意思,盡管有些JVM大多沒(méi)有這一代。主要存放常量及類(lèi)的一些信息默認(rèn)最小值為16MB,最大值為64MB,可通過(guò)-XX:PermSize及-XX:MaxPermSize來(lái)設(shè)置最小值和最大值。
常見(jiàn)的GC算法:
標(biāo)記-清除算法(Mark-Sweep)
就是分為標(biāo)記和清除兩個(gè)階段進(jìn)行處理內(nèi)存中的對(duì)象缺點(diǎn):
效率問(wèn)題,標(biāo)記和清除兩個(gè)過(guò)程的效率都不高;
空間問(wèn)題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
復(fù)制算法(Copying)
將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。
當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過(guò)的內(nèi)存空間一次清理掉。反復(fù)去交換兩個(gè)內(nèi)存的角色,完成垃圾收集
java中新生代的from和to空間就是使用這個(gè)算法
優(yōu)點(diǎn):這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等。復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。只是這種算法的代價(jià)是將內(nèi)存縮小為了原來(lái)的一半,未免太高了一點(diǎn)。
缺點(diǎn):復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)變低(所以eden區(qū)沒(méi)有采用這個(gè)算法)
分代收集算法(Generational Collection)
1、根據(jù)對(duì)象存活周期的不同將內(nèi)存劃分為幾塊。
2、一般是把Java堆分為新生代和老年代,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ā?br /> 3、在新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去(回收頻率很高),只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集。
其中,新生代又細(xì)分為三個(gè)區(qū):Eden,From Survivor,ToSurviver,比例是8:1:1
4、老年代中因?yàn)閷?duì)象存活率高、沒(méi)有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來(lái)進(jìn)行回收。
分區(qū)算法
其主要就是將整個(gè)內(nèi)存分為N個(gè)多小的獨(dú)立空間,每個(gè)小空間都可以獨(dú)立使用,這樣細(xì)粒度的控制一次回收都少個(gè)小空間和那些個(gè)小空間,而不是對(duì)整個(gè)空間進(jìn)行GC,從而提升性能,并減少GC的停頓時(shí)間。
GC算法優(yōu)劣標(biāo)準(zhǔn)
評(píng)價(jià)一個(gè)垃圾收集GC算法的兩個(gè)標(biāo)準(zhǔn)
吞吐量(throughput)越高算法越好
暫停時(shí)間(pause times)越短算法越好
停頓
一個(gè)時(shí)間段內(nèi)應(yīng)用程序線程讓GC線程執(zhí)行而完全暫停。
垃圾回收器的任務(wù)是識(shí)別和回收垃圾對(duì)象進(jìn)行內(nèi)存清理,為了讓垃圾回收器可以高效的執(zhí)行,大部分情況下,會(huì)要求系統(tǒng)進(jìn)入一個(gè)停頓的狀態(tài)。停頓的目的是終止所有應(yīng)用線程,只有這樣系統(tǒng)才不會(huì)有新的垃圾產(chǎn)生,同時(shí)停頓保證了系統(tǒng)狀態(tài)在某一個(gè)瞬間的一致性,也有益于更好地標(biāo)記垃圾對(duì)象,因此垃圾回收時(shí),都會(huì)產(chǎn)生應(yīng)用程序的停頓
原文鏈接:https://blog.csdn.net/w372426096/article/details/81360083
總結(jié)
以上是生活随笔為你收集整理的网易(杭州研究所)初面的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 大连商务英语百家外语商务英语与普通英语有
- 下一篇: 发生身份验证错误,要求的函数不受支持