序:很久沒寫博客啦,各項事情塵埃落定,先輸出一波之前找工作時候記錄的一些東西
阻塞、非阻塞、同步、異步 的區別
- 阻塞
阻塞調用是指調用結果返回之前,當前線程會被掛起(線程進入非可執行狀態,在這個狀態下,cpu 不會給線程分配時間片,即線程暫停運行)。函數只有在得到結果之后才會返回。對於同步調用來說,很多時候當前線程還是激活的,只是從邏輯上當前函數沒有返回而已。 就是調用我(函數),我(函數)沒有接收完數據或者沒有得到結果之前,我不會返回。 - 非阻塞
指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。就是調用我(函數),我(函數)立即返回,通過 select 通知調用者 - 同步 IO
同步 IO 進行 IO 操作時會阻塞進程。IO 操作分兩個階段(數據准備和拷貝數據),阻塞 IO 是這兩步都阻塞,非阻塞 IO 是數據准備階段,不會阻塞進程。數據准備完成后,進程主動在此調用 recvfrom 函數將數據從內核拷貝到用戶內存
- 異步IO
相當於用戶進程將 IO 操作整個交給內核去完成,內核會返回事件完成通知。在此階段,用戶進程不需要檢查 IO 操作狀態,也不需要主動拷貝數據,用戶進程完全沒有阻塞
數據庫 ACID 一致性和原子性的區別
ACID特性,原子性、一致性、隔離性、持久性
- 原子性
是指事務是一個不可再分割的工作單位,事務中的操作要么都發生,要么都不發生。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣 - 一致性
一致性是指事務使得系統從一個一致的狀態轉換到另一個一致狀態。這是說數據庫事務不能破壞關系數據的完整性以及業務邏輯上的一致性
- 隔離性
多個事務並發訪問時,事務之間是隔離的,一個事務不應該影響其它事務運行效果。這指的是在並發環境中,當不同的事務同時操縱相同的數據時,每個事務都有各自的完整數據空間。由並發事務所做的修改必須與任何其他並發事務所做的修改隔離
- 持久性
持久性,意味着在事務完成以后,該事務所對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾。即使出現了任何事故比如斷電等,事務一旦提交,則持久化保存在數據庫中
Mysql如何保證事務的ACID特性
-
原子性
undolog記錄反向操作,用於回滾:
對於每一個insert,undolog記錄一個delete
對於每一個delete,undolog記錄一個insert
對於每一個update,undolog記錄一個相反的update -
一致性
redolog+undolog ,保證所有操作同時提交和回滾。
通過加鎖保證同一行數據更新串行,避免提交丟失。
通過MVCC保證事務內讀一致性。
加鎖參考 -
隔離性
通過隔離模式實現不同級別下的隔離性。
通過鎖和MVCC實現隔離模式下的讀寫並行。
[四種隔離模式]https://success.blog.csdn.net/article/details/105027900
[加鎖原理]https://success.blog.csdn.net/article/details/103154299 -
持久性
通過redolog實現持久性。
sync_binlog和innodb_flush_log_at_trx_commi設置為1,也就是大家常說的雙1策略,保證宕機數據不丟失。
宕機重啟時通過對比redolog頁和數據頁的LSN(Log Sequence Number)進行恢復
常見排序算法,說下快排過程,時間復雜度
有N個節點的滿二叉樹的高度
1+logN
單元點最短路的方法,時間復雜度
如何實現關鍵字輸入提示,使用字典樹,復雜度多少,有沒有其他方案,答哈希,如果是中文呢,分詞后建立字典樹
紅黑樹的結構,查詢性能
死鎖是怎么產生的
線程和進程的區別
進程的通信方式
CPU的執行方式
代碼中遇到進程阻塞,進程僵死,內存泄漏等情況怎么排查。通過ps查詢狀態,分析dump文件等方式排查
Linux了解么,查看進程狀態ps,查看cpu狀態 top。查看占用端口的進程號netstat grep
10g文件,只有2g內存,怎么查找文件中指定的字符串出現位置。MapReduce分割文件處理,他說可以用cat | grep 管道處理
Linux的swap了解么
MySQL的存儲引擎,有什么區別
100w個數,怎么找到前1000個最大的,堆排序,怎么構造,怎么調整,時間復雜度
一個矩陣,從左上角到右下角,每個位置有一個權值。可以上下左右走,到達右下角的路徑權值最小怎么走
四輛小車,每輛車加滿油可以走一公里,問怎么能讓一輛小車走最遠
MySQL的索引,B+樹性質
Linux的cpu 100怎么排查,top jstack,日志,gui工具
Linux大文件怎么查某一行的內容
十億個數的集合和10w個數的集合,如何求它們的交集 (集合的數字不重復)
十億和數找到前100個最大的,堆排序
TCP和UDP的區別,具體使用場景呢
TCP四次揮手講一下過程
對於socket編程,accept方法是干什么的,在三次握手中屬於第幾次
對於單例模式,有什么使用場景了,講了全局id生成器,他問我分布式id生成器怎么實現
除了單例模式,知道適配器模式怎么實現么,有什么用
proc文件系統
TCP和UDP的核心區別在哪,講了滑動窗口保證可靠有序傳輸,UDP不可靠。TCP需要連接而UDP不需要
TCP的四次揮手,time wait狀態有什么意義
map 和 set 底層是用什么數據結構實現?用 set 實現 map?(set<pair<key, value>>)
遞歸調用函數占用了什么空間
棧空間
實際上堆空間也有可能占用
函數棧空間多大
函數傳參時int &會減少占用的空間嗎,有好處嗎
基礎類型(不會)
感覺從內存上講沒好處,看需求把,是否需要改那個數。
引用占不占內存
1,引用實際是通過指針實現的。
2,引用是一個常量指針。
3,引用在內存中占4個字節。
4,在對引用定義時,需要對這個常量指針初始化。
5,因為在在表達式中,使用引用實際上就像使用變量本身一樣,所以直接用sizeof是得不到引用本身的大小的。
HTTP協議
簡單介紹,協議細節和包含了什么
-
請求報文
請求行
請求方法 URL 版本協議
請求頭部
請求數據 -
響應報文
狀態行
版本協議 狀態碼 狀態碼描述
響應頭部
connection
響應正文
http常見狀態碼
http常見請求方法 (get,post, push)
STL常用的容器有哪些
講一講容器的內部實現,擴容縮容,存儲
vector內存結構,擴容縮容
string擴容縮容,連續的
string是連續的
優先級隊列,以vector為存儲結構的堆
面向對象思想的特點
- 封裝多態繼承
哪些語言特性體現面向對象
- 多態
多態通過什么實現的
多態和重載區別
- 多態
通過虛函數表實現
一個接口,根據調用的對象不同產生不同的結果
- 重載
通過參數列表的不同實現根據輸入參數類型不同選擇對應的函數
- 重寫和重載的區別
重載是相同函數名,但函數的參數不能完全相同。重寫是指派生類改寫基類虛函數的函數體
虛函數繼承機制與內部實現
類的大小
int成員+普通函數+虛函數 類大小是多少 sizeof 為 8
字節對齊的理解
為什么要字節對齊
怎么字節對齊
不對齊會怎么樣
對齊與不對齊的訪問內存區別
字節序
大端小端的區別
小端(先存小的) 數值高位 放在內存低位
網絡序(默認大端序)
字節序怎么轉換
int的怎么實現
string有字節序的說法嗎
沒有,字節序是指byte的排序,string里面都是char,一個char就是1字節
只要出現索引的地方,一定是索引越大地址越大
四次揮手
2msl
半連接狀態
內存碎片分為哪幾種
內碎片外碎片
有序數組中找是否有兩個數和為N
Linux命令的使用,查看進程、查看資源占用、查看某一個進程的資源占用
進程、線程及協程及使用場景
多線程哪些東西是共享的
靜態變量共享嗎
虛擬內存地址的組織
tcp擁塞控制
慢啟動和快重傳的觸發條件
怎么區分是網絡的原因(連發3次ack說明丟包)
udp改可靠udp怎么做
對着tcp的可靠傳輸方法改
加ack
加序號
擁塞控制
stl標准庫六大容器
vector內存
map的實現方式
共享內存
進程重啟如何讀到之前的東西(比如本來有個map,重啟后繼續讀到)
共享內存可以實現的
設計一個算法
紅包算法,3個人搶5塊的紅包,每個人不能超過2塊
先每人分2塊,再加權取隨機數按比例加權扣一元
epoll兩種模式的區別
- LT 模式
當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程序,應用程序可以不立即處理該事件。下次調用 epoll_wait 時,會再次響應應用程序並通知此事件。
一個 socket 第一次有數據,LT 模式下檢測到 socket 處於活躍狀態,接下來再有數據過來,接着觸發。或者說可以根據需要收取部分數據,只要 socket 上數據不收取完,epoll_wait 會接着返回這個可讀 socket。編程上如果需要數據包一部分一部分的處理,可以使用 LT 模式 - ET 模式
當 epoll_wait 檢測到描述符事件發生並將此事件通知應用程序,應用程序必須立即處理該事件。如果不處理,下次調用 epoll_wait 時,不會再次響應應用程序並通知此事件。第一次有數據會觸發 socket,第二次再有數據不會觸發,必須等第一次的數據完全讀完或寫完。必須把當前 socket 數據全部收完,才能接受下一次的可讀 socket編程上 ET 模式必須是一個循環,收取數據到 recv 返回-1,errno=EAGAIN - epoll 的 ET 模式為什么一定要使用非阻塞 IO
ET 模式下每次 write 或 read 需要循環 write 或 read 直到返回 EAGAIN 錯誤。以讀操作為例,這是因為 ET 模式只在 socket 描述符狀態發生變化時才觸發事件,如果不一次把 socket 內核緩沖區的數據讀完,會導致 socket 內核緩沖區中即使還有一部分數據,該 socket 的可讀事件也不會被觸發。根據上面的討論,若 ET 模式下使用阻塞 IO,則程序一定會阻塞在最后一次 write 或 read 操作,因此說 ET 模式下一定要使用非阻塞 IO
google.com屏蔽的原理是什么,隧道怎么實現的
隧道上網原理
進程調度
進程調度:記錄系統中的所有進程的狀態、優先級數和資源的需求情況確定調度算法,決定將 CPU 分配給哪個進程多少時間分配處理機給進程,進行 CPU 現場的保護和移交
進程調度算法:先來先服務調度算法、短作業優先調度算法、非搶占式優先級調度算法、搶占式優先級調度算法、高響應比優先調度算法、時間片輪轉法調度算法
頁面置換算法
- 先進先出頁面置換算法(FIFO)及其改進
這種算法的思想和隊列是一樣的,OS維護一個當前在內存中的所有頁面的鏈表,最新進入的頁面在尾部,最久的在頭部,每當發生缺頁中斷,就替換掉表頭的頁面並且把新調入的頁面加入到鏈表末尾。
一種合理的改進,稱為第二次機會算法。即給每個頁面增加一個R位,每次先從鏈表頭開始查找,如果R置位,清除R位並且把該頁面節點放到鏈表結尾;如果R是0,那么就是又老又沒用到,替換掉
- 最佳頁面置換算法(OPT)
最理想的狀態下,我們給頁面做個標記,挑選一個最遠才會被再次用到的頁面。當然,這樣的算法不可能實現,因為不確定一個頁面在何時會被用到。
- 最近最久未使用(NRU)
系統為每一個頁面設置兩個標志位:當頁面被訪問時設置R位,當頁面(修改)被寫入時設置M位。當發生缺頁中斷時,OS檢查所有的頁面,並根據它們當前的R和M位的值,分為四類:
(1)!R&!M(2)!R&M(3)R&!M(4)R&M
編號越小的類,越被優先換出。即在最近的一個時鍾滴答內,淘汰一個沒有被訪問但是已經被修改的頁面,比淘汰一個被頻繁使用但是“clean”的頁面要好。
- 最近最少使用置換算法(LRU)
最近最少使用,簡單來說就是將數據塊中,每次使用過的數據放在數據塊的最前端,然后將存在的時間最長的,也就是數據塊的末端的數據剔除掉這就是 LRU 算法
操作系統的CPU如何調度
同進程調度
介紹下epoll,基本使用,lt/et,什么時候文件描述符活躍,活躍后內核如何處理。和select有什么區別
介紹下tcp/ip四層協議
TCP/IP協議並不完全符合OSI 標准定制的七層參考模型,它采取了四層的層級結構
網絡接口層:接收IP數據包並進行傳輸,從網絡上接收物理幀,抽取IP 轉交給下一層,對實際網絡的網絡媒體的管理,定義如何使用物理網絡 ,如以太網。
網際層IP: 負責提供基本的數據封包傳送功能,讓每一塊數據包都能打到目的主機,但不檢查是否被正確接收,主要表現為IP協議
傳輸層:在此層中,它提供了節點的數據傳送,應用程序之間的通信服務,主要是數據格式化,數據確認和丟失重傳等。主要協議包括TCP和UDP
應用層:應用程序間溝通單層,如萬維網(WWW)、簡單電子郵件傳輸(SMTP)、文件傳輸協議(FTP)、網絡遠程訪問協議(Telnet)等
ping通過什么協議,在哪一層
Ping 是一個應用程序,是基於 ICMP 協議實現的。ICMP 協議是位於 IP 層的一個協議。它是 TCP/IP 協議族的一個子協議,用於在 IP 主機、路由器之間傳遞控制消息。
Ping 命令的基本原理?答:ICMP,發送主機發送 echo 請求,接受主機回復 echo 報文
Ping 的如果是域名,還要先經過 DNS 解析
介紹三次握手四次揮手,服務器能否不wait直接斷開
- time_wait 狀態如何避免
首先服務器可以設置 SO_REUSEADDR 套接字選項來通知內核,如果端口忙,但 TCP 連接位於 TIME_WAIT 狀態時可以重用端口。在一個非常有用的場景就是,如果你的服務器程序停止后想立即重啟,而新的套接字依舊希望使用同一端口,此時 SO_REUSEADDR 選項就可以避免TIME_WAIT 狀態
心跳包通過什么實現的,如何調節參數
因為要考慮到一個服務器通常會連接多個客戶端,因此由用戶在應用層自己實現心跳包,代碼較多 且稍顯復雜,而利用TCP/IP協議層為內置的KeepAlive功能來實現心跳功能則簡單得多。 不論是服務端還是客戶端,一方開啟KeepAlive功能后,就會自動在規定時間內向對方發送心跳包, 而另一方在收到心跳包后就會自動回復,以告訴對方我仍然在線。 因為開啟KeepAlive功能需要消耗額外的寬帶和流量,所以TCP協議層默認並不開啟KeepAlive功 能,盡管這微不足道,但在按流量計費的環境下增加了費用,另一方面,KeepAlive設置不合理時可能會 因為短暫的網絡波動而斷開健康的TCP連接。並且,默認的KeepAlive超時需要7,200,000 MilliSeconds, 即2小時,探測次數為5次。對於很多服務端應用程序來說,2小時的空閑時間太長。因此,我們需要手工開啟KeepAlive功能並設置合理的 KeepAlive參數
心跳包一般來說都是在邏輯層發送空的echo包來實現的。下一個定時器,在一定時間間隔下發送一個空包給客戶端,然后客戶端反饋一個同樣的空包回來,服務器如果在一定時間內收不到客戶端發送過來的反饋包,那就只有認定說掉線了
malloc如何實現的,通過哪個系統調用開辟內存,如何映射到物理內存
- 當分配內存小於 128K 時,brk 是將數據段(.data)的最高地址指針_edata 往高地址推
- 當分配內存大於 128K 時,mmap 是在進程的虛擬地址空間中(堆和棧中間,稱為文件映射區域的地方)找一塊空閑的虛擬內存
這兩種方式分配的都是虛擬內存,沒有分配物理內存。在第一次訪問已分配的虛擬地址空間的時候,發生缺頁中斷,操作系統負責分配物理內存,然后建立虛擬內存和物理內存之間的映射關系
mysql,acid,mvcc,版本號加在哪,跨表怎么辦
介紹下B+樹,數據存在哪,數據具體存的哪些?
死機了數據怎么恢復?有幾種log形式?
詳細
持久性是指一個事務一旦被提交了,那么對數據庫中的數據的改變就是永久性的,即便是在數據庫系統遇到故障的情況下也不會丟失提交事務的操作。
MySQL采用了一種叫WAL(Write Ahead Logging)提前寫日志的技術。意思就是說,發生了數據修改操作先寫日志記錄下來,等不忙的時候再持久化到磁盤。這里提到的日志就是redo log。
redo log稱為重做日志,當有一條記錄需要修改的時候,InnoDB引擎會先把這條記錄寫到redo log里面。redo log是物理格式日志,它記錄的是對於每個頁的修改。
redo log是由兩部分組成的:一是內存中的重做日志緩沖(redo log buffer);二是用來持久化的重做日志文件(redo log file)。為了消耗不必要的IO操作,事務再執行過程中產生的redo log首先會redo log buffer中,之后再統一存入redo log file刷盤進行持久化,這個動作稱為fsync
binlog記錄了mysql執行更改了所有操作,但不包含select和show這類本對數據本身沒有更改的操作。但是不是說對數據本身沒有修改就不會記錄binlog日志。
- binlog是mysql自帶的,他會記錄所有存儲引擎的日志文件。而redo log是InnoDB特有的,他只記錄該存儲引擎產生的日志文件
- binlog是邏輯日志,記錄這個語句具體操作了什么內容。Redo log是物理日志,記錄的是每個頁的更改情況
- redo log是循環寫,只有那么大的空間。binlog采用追加寫入,當一個binlog文件寫到一定大小后會切換到下一個文件
線程池如何實現的?
在應用程序啟動之后,就馬上創建一定數量的線程,放入空閑的隊列中。這些線程都是處於阻塞狀態,這些線程只占一點內存,不占用 CPU。當任務到來后,線程池將選擇一個空閑的線程,將任務傳入此線程中運行。當所有的線程都處在處理任務的時候,線程池將自動創建一定的數量的新線程,用於處理更多的任務。執行任務完成之后線程並不退出,而是繼續在線程池中等待下一次任務。當大部分線程處於阻塞狀態時,線程池將自動銷毀一部分的線程,回收系統資源。
epoll想改成多線程的該怎么實現?
單獨單寫設計阻塞隊列,不用鎖怎么實現?
使用一個全局變量進行標志
std:move介紹下,什么是左值右值,傳遞個對象會什么樣?連續執行兩次move會怎么樣
取地址的、有名字的就是左值。左值的生存期長,可以作為賦值的對象。
右值指臨時對象,只在當前語句有效,右值又可以細分為純右值、將亡值。純右值指的是臨時變量和不跟對象關聯的字面量值;將亡值則是 C++11 新增的跟右值引用相關的表達式,這樣表達式通常是將要被移動的對象(移為他用)。如std::move 的返回值。將亡值可以理解為通過“盜取”其他變量內存空間的方式獲取到的值
std::move()將左值強制轉換為右值。
智能指針介紹一下,unique如何防止多次釋放
shared_ptr、unique_ptr、weak_ptr。shared_ptr多個指針指向相同的對象。shared_ptr 使用引用計數,每一個 shared_ptr 的拷貝都指向相同的內存。每使用他一次,內部的引用計數加 1,每析構一次,內部的引用計數減 1,減為 0 時,自動刪除所指向的堆內存。shared_ptr 內部的引用計數是線程安全的,但是對象的讀取需要加鎖。
unique_ptr“唯一”擁有其所指對象,同一時刻只能有一個 unique_ptr 指向給定對象(通過禁用拷貝構造函數和賦值運算符、只有移動語義來實現)。
對象互相引用
當父類對象包含子類對象且子類對象包含父類對象,然二者又互相賦值的時候,將會發生互相引用的情況,資源將得不到釋放。
弱指針 weak_ptr 不控制對象的生命期,指向一個shared_ptr 管理的對象,但是引用計數不在進行加 1。
它只可以從一個 shared_ptr 或另一個 weak_ptr 對象構造。,然后賦值給它的構造和析構不會引起引用記數的增加或減少.防止兩個 shares_ptr 互相引用使得釋放時引用計數為 1,無法得到釋放。不能通過 weak_ptr 直接訪問對象的方法,需要先將 weak_ptr 轉為shared_ptr,才可以。某個 weak_ptr 調用 lock()轉變為 shared_ptr。也可以 weak..直接賦值給 shared…
map和unordered_map的區別
- unordered_map 和 map 類似,都是存儲的 key-value 的值,可以通過 key 快速索引到 value。不同的是 unordered_map 不會根據 key 的大小進行排序
- unordered_map 的底層實現是 hash_table,map 中的元素是按照紅黑樹存儲
- 如果需要內部元素自動排序,使用 map,不需要排序使用 unordered_map
介紹下deque
雙端隊列(deque)是一種支持向兩端高效地插入數據、支持隨機訪問的容器。和 vector 容器采用連續的線性空間不同,deque 容器存儲數據的空間是由一段一段等長的連續空間構成,各段空間之間並不一定是連續的,可以位於在內存的不同區域。為了管理這些連續空間,deque 容器用數組(數組名假設為 map)存儲着各個連續空間的首地址。也就是說,map 數組中存儲的都是指針,指向那些真正用來存儲數據的各個連續空間
當 deque 容器需要在頭部或尾部增加存儲空間時,它會申請一段新的連續空間,同時在 map 數組的開頭或結尾添加指向該空間的指針,由此該空間就串接到了 deque 容器的頭部或尾部。如果 map 數組滿了怎么辦?很簡單,再申請一塊更大的連續空間供 map 數組使用,將原有數據(很多指針)拷貝到新的 map 數組中,然后釋放舊的空間。
伙伴系統
Linux 內核中引入了伙伴系統算法(buddy system)。把所有的空閑頁框分組為 11 個塊鏈表,每個塊鏈表分別包含大小為 1,2,4,8,16,32,64,128,256,512 和 1024 個連續頁框的頁框塊。最大可以申請 1024 個連續頁框,對應 4MB 大小的連續內存。每個頁框塊的第一個頁框的物理地址是該塊大小的整數倍。
假設要申請一個 256 個頁框的塊,先從 256 個頁框的鏈表中查找空閑塊,如果沒有,就去 512 個頁框的鏈表中找,找到了則將頁框塊分為 2 個 256 個頁框的塊,一個分配給應用,另外一個移到 256 個頁框的鏈表中。如果 512 個頁框的鏈表中仍沒有空閑塊,繼續向 1024 個頁框的鏈表查找,如果仍然沒有,則返回錯誤。頁框塊在釋放時,會主動將兩個連續的頁框塊合並為一個較大的頁框塊。
linux查詢進程的CPU占用,打開的端口號,TCP連接數量,內存使用情況
top, ps, lsof, netstat, df -h
查看程序對應的進程號: ps -ef | grep 進程名字
查看進程號所占用的端口號: netstat -nltp | grep 進程號
查看端口號所使用的進程號: lsof -i:端口號
多線程是如何通信的
重載和重寫
什么時候設置成虛函數
https加密過程
指針和引用的區別
new和malloc區別
智能指針(auto_ptr,shared_ptr區別)
線程同步,進程同步方法
說一下四次揮手,為什么要有time-wait
分配內存的時候操作系統做了什么事情
epoll和select的區別
epoll的源代碼讀過嗎?描述一下其中的數據結構
epoll發展於介紹
epoll中就緒列表引用着就緒的socket,所以它應能夠快速的插入數據。程序可能隨時調用epoll_ctl添加監視socket,也可能隨時刪除。當刪除時,若該socket已經存放在就緒列表中,它也應該被移除。所以就緒列表應是一種能夠快速插入和刪除的數據結構。雙向鏈表就是這樣一種數據結構,epoll使用雙向鏈表來實現就緒隊列。
既然epoll將“維護監視隊列”和“進程阻塞”分離,也意味着需要有個數據結構來保存監視的socket。至少要方便的添加和移除,還要便於搜索,以避免重復添加。紅黑樹是一種自平衡二叉查找樹,搜索、插入和刪除時間復雜度都是O(log(N)),效率較好。epoll使用了紅黑樹作為索引結構
如果epoll_wait函數中定時了3秒,有事情和沒事情返回接口會發生什么?
學校局域網到公共網時路由器是怎么變化的
一個阻塞的io進程是如何被調度的?(操作系統會一直等待嗎?還是會定時去拉一把?
IO 准備好 / Sleep 時間到 前不會調度該線程
tcpdump抓包
IO復用(select/poll/epoll)區別
非關系型數據庫和關系型數據庫區別
分布式事務
Git
git,新建一個分支、比較兩個分支差異、合並分支
kill -9 與 kill -5的差別
linux:找一個文件夾下帶某一個關鍵字的文件
TCP 和 UDP 區別?
TCP 是怎么保障可靠性的
三次握手四次揮手過程
信號量與信號的區別和應用場景?
什么是中斷?什么是陷入?
中斷是指計算機運行過程中,出現某些意外情況需主機干預時,機器能自動停止正在運行的程序並轉入處理新情況的程序,處理完畢后又返回原被暫停的程序繼續運行.
-
硬件中斷
-
軟件中斷
是一條CPU指令,用以自陷一個中斷。由於軟中斷指令通常要運行一個切換CPU至內核態(Kernel Mode/Ring 0)的子例程,它常被用作實現系統調用(System call)
- 中斷處理流程
1、設備發出中斷信號
2、硬件通過 PSW 和 PC 保存現場,保存在堆棧中
3、根據中斷碼查找中斷向量表
4、把中斷處理程序入口地址推送給寄存器
5、執行中斷處理程序
6、回到之前斷點繼續運行
字節碼層面如何體現多態
緩存穿透,緩存雪崩,緩存擊穿,緩存過期策略
- 緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據,而用戶不斷發起請求,如發起為id為“-1”的數據或id為特別大且不存在的數據。這時的用戶很可能是攻擊者,攻擊會導致數據庫壓力過大。
解決方案:
- 接口層增加校驗,如用戶鑒權校驗,id做基礎校驗,id<=0的直接攔截;
從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將key-value對寫為key-null,緩存有效時間可以設置短點,如30秒(設置太長會導致正常情況也沒法使用)。這樣可以防止攻擊用戶反復用同一個id暴力攻擊
- 緩存擊穿
緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於並發用戶特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造成過大壓力
解決方案:
設置熱點數據永遠不過期
加互斥鎖降低從數據庫中讀取數據頻率
- 緩存雪崩
緩存雪崩是指緩存中數據大批量到過期時間,而查詢數據量巨大,引起數據庫壓力過大甚至down機。和緩存擊穿不同的是,緩存擊穿指並發查同一條數據,緩存雪崩是不同數據都過期了,很多數據都查不到從而查數據庫
解決方案:
- 緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生。
- 如果緩存數據庫是分布式部署,將熱點數據均勻分布在不同搞得緩存數據庫中。
- 設置熱點數據永遠不過期。
緩存與數據庫的一致性
對內存泄漏的理解,以及在項目中如何排查解決
內存泄漏是指由於疏忽或錯誤造成了程序未能釋放掉不再使用的內存的情況。內存泄漏並非指內存在物理上消失,而是應用程序分配某段內存后,由於設計錯誤,失去了對該段內存的控制。
檢查方法:在 main 函數最后面一行,加上一句_CrtDumpMemoryLeaks()。調試程序,自然關閉程序讓其退出,查看輸出:
輸出這樣的格式{453}normal block at 0x02432CA8,868 bytes long 被{}包圍的 453 就是我們需要的內存泄漏定位值,868 bytes long 就是說這個地方有 868 比特內存沒有釋放。
定位代碼位置
在 main 函數第一行加上_CrtSetBreakAlloc(453);意思就是在申請 453這塊內存的位置中斷。然后調試程序,程序中斷了,查看調用堆棧。加上頭文件#include <crtdbg.h>
大數據量分庫分表方式,作用
數據庫災備方案
vector如何實現線程安全
自旋鎖
輸入url后發生了什么(詳細介紹整個過程)
純虛函數與虛函數的區別
MySQL索引、聯合索引、聯合索引應用特點
explain sql語句(我回答的是possible_keys、key、type等)
TCP三次握手、DNS負載均衡、長短連接
設計模型(口述下工廠、單例的寫法)
查一個文件中含有某個關鍵字的行數
mysql中的視圖
改變一個視圖其它事務能看到嗎
mysql為什么用b+樹
線程如何調度
多路復用
消息隊列
1.什么是消息隊列
2.如何保證消息不丟失
3.如何保證消息不重復
如何保證線程安全
B+樹索引說說
MySQL半同步復制過程
- 異步復制(Asynchronous replication)
MySQL默認的復制即是異步的,主庫在執行完客戶端提交的事務后會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主如果crash掉了,此時主上已經提交的事務可能並沒有傳到從上,如果此時,強行將從提升為主,可能導致新主上的數據不完整。 - 全同步復制(Fully synchronous replication)
指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。因為需要等待所有從庫執行完該事務才能返回,所以全同步復制的性能必然會收到嚴重的影響。 - 半同步復制(Semisynchronous replication)
介於異步復制和全同步復制之間,主庫在執行完客戶端提交的事務后不是立刻返回給客戶端,而是等待至少一個從庫接收到並寫到relay log中才返回給客戶端。相對於異步復制,半同步復制提高了數據的安全性,同時它也造成了一定程度的延遲,這個延遲最少是一個TCP/IP往返的時間。所以,半同步復制最好在低延時的網絡中使用。
HTTPS握手過程(是SSL的握手)
HTTPs 是以安全為目標的 HTTP 通道,簡單講是 HTTP 的安全版,即HTTP 下加入 SSL 層,HTTPS 的安全基礎是 SSL,因此加密的詳細內容就需要 SSL
HTTPs的握手過程包含五步
- 瀏覽器請求連接
- 服務器返回證書:證書里面包含了網站地址,加密公鑰,以及證書的頒發機構等信息,服務器采用非對稱加密算法(RSA)生成兩個秘鑰,私鑰自己保留
- 瀏覽器收到證書后作以下工作:
3.1 驗證證書的合法性
3.2 生成隨機(對稱)密碼,取出證書中提供的公鑰對隨機密碼加密;瀏覽器即客戶端使用非對稱加密來加密對稱加密規則,對稱加密用於加密后續傳輸的信息
3.3 將之前生成的加密隨機密碼等信息發送給網站- 服務器收到消息后作以下的操作
4.1 使用自己的私鑰解密瀏覽器用公鑰加密后的消息,並驗證 HASH 是否與瀏覽器發來的一致;獲得瀏覽器發過來的對稱秘鑰
4.2 使用加密的隨機對稱密碼加密一段消息,發送給瀏覽器- 瀏覽器解密並計算握手消息的 HASH:如果與服務端發來的 HASH 一致,此時握手過程結束,之后進行通信
c++ 11特性知道那些
tcp的幾個字段ack,psh,rst之類什么作用
SYN表示建立連接,
FIN表示關閉連接,
ACK表示響應,
PSH表示有 DATA數據傳輸,
RST表示連接重置
c++吐核,原因,怎么排查,爆棧怎么查
分布式鎖怎么實現的
c++的智能指針
虛擬地址空間
大端小端問題,怎樣通過網絡發送(考察網絡序主機序轉換的問題)
大端模式:是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址端。
小端模式,是指數據的高字節保存在內存的高地址中,低位字節保存在在內存的低地址端
網絡字節序類似於大端模式,因為UDP/TCP/IP協議規定:把接收到的第一個字節當作高位字節看待,類似於大端模式低地址存放高字節的存儲方式,實際上也確實像,因為無論是收還是發,都是從低字節開始的,那么收到的第一個字節理應放到低地址。
場景題
#### 朋友之間的點對點關系用圖維護,怎么判斷兩人是否是朋友,並查集,時間復雜度,過程
程序現在CPU突然爆了,如何定位
給定某天 200 萬用戶登錄日志(用戶,登入登出時間),求某一時間點用戶在線人數
兩個小頂堆的優先隊列,O(n)即可解決
如何從幾億個數中找到唯一出現的一個數(內存無法一次讀取全部數據)
1G內存對1個T的數據進行排序
算法
最長回文子串
每K節點反轉鏈表
class Solution {
public:
// 翻轉一個子鏈表,並且返回新的頭與尾
pair<ListNode*, ListNode*> myReverse(ListNode* head, ListNode* tail) {
ListNode* prev = tail->next;
ListNode* p = head;
while (prev != tail) {
ListNode* nex = p->next;
p->next = prev;
prev = p;
p = nex;
}
return {tail, head};
}
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* hair = new ListNode(0);
hair->next = head;
ListNode* pre = hair;
while (head) {
ListNode* tail = pre;
// 查看剩余部分長度是否大於等於 k
for (int i = 0; i < k; ++i) {
tail = tail->next;
if (!tail) {
return hair->next;
}
}
ListNode* nex = tail->next;
pair<ListNode*, ListNode*> result = myReverse(head, tail);
head = result.first;
tail = result.second;
// 把子鏈表重新接回原鏈表
pre->next = head;
tail->next = nex;
pre = tail;
head = tail->next;
}
return hair->next;
}
};
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if (k <= 1) return head;
vector<ListNode* > vec;
while (head) {
vec.emplace_back(head);
head = head->next;
}
if (vec.size() < k) return head;
ListNode* newHead = vec[k - 1];
for (int i = 1; i < k; ++i) {
vec[i]->next = vec[i - 1];
}
int last_index = 0;
if (vec.size() == k) {
vec[0]->next = nullptr;
return vec[k - 1];
}
int j = k, tmp;
while (j < vec.size()) {
tmp = last_index + k - 1;
if (tmp + 1 < vec.size()) vec[tmp + 1]->next = nullptr;
if (tmp + k >= vec.size()) {
if(tmp+2 < vec.size()) vec[tmp+1]->next = vec[tmp+2];
vec[last_index]->next = vec[tmp + 1];
return newHead;
}
j = tmp + 2;
for (; j < vec.size() && j - tmp <= k; ++j) {
vec[j]->next = vec[j - 1];
}
vec[last_index]->next = vec[j - 1];
last_index = tmp + 1;
}
return newHead;
}
};
兩個字符串的最長公共子串
范圍1到1000的數,原本有1000個,互不重復,現多出來1個重復的數,怎么找到他,統計次數,太慢,求和相減
N個糖果,每次只能取1個到6個,不能不取,你先取,請問是否有必勝策略,怎么取
找出規律不能為7的倍數,每次取到只剩7的倍數個糖果即可
八皇后的代碼填空題
二分查找
海量數據topK的問題
合並有序鏈表
對稱的數字
排序數組二分查找
左上角到右下角的路有幾條?(中間存在障礙)
https://leetcode-cn.com/problems/unique-paths-ii/
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
vector<vector<int>> vvi(obstacleGrid.size(), vector<int>(obstacleGrid[0].size(), 0));
if(obstacleGrid[0][0]) return 0;
vvi[0][0] = 1;
for(int j =1;j < obstacleGrid[0].size();j++){
if(obstacleGrid[0][j]) break;
vvi[0][j] = 1;
}
for(int i = 1;i < obstacleGrid.size();i++){
if(obstacleGrid[i][0]) break;
vvi[i][0] = 1;
}
for(int i = 1;i < obstacleGrid.size();i++){
for(int j = 1;j < obstacleGrid[0].size();j++){
if(obstacleGrid[i][j]) continue;
vvi[i][j] = vvi[i-1][j]+vvi[i][j-1];
}
}
return vvi[obstacleGrid.size()-1][obstacleGrid[0].size()-1];
}
};
跳台階問題
選硬幣問題
twoSum
反轉鏈表+判斷棧是否合法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head || !head->next) return head;
ListNode *t1 = head, *t2 = head->next, *t3;
head->next = nullptr;
while(t2){
t3 = t2->next;
t2->next = t1;
t1 = t2;
t2 = t3;
}
return t1;
}
};