4.1 計(jì)算機(jī)體系結(jié)構(gòu)(Computer Architecture)
4.1.1 馮·諾依曼結(jié)構(gòu)
兩個(gè)深遠(yuǎn)影響的觀點(diǎn):
采用二進(jìn)制,拋棄十進(jìn)制
程序存儲(chǔ)(stored-program)

4.1.2 哈佛結(jié)構(gòu)
對(duì)馮諾依曼結(jié)構(gòu)的改進(jìn)與完善,區(qū)別在指令與數(shù)據(jù)并不保存在同一個(gè)存儲(chǔ)器。
這意味著:
指令與數(shù)據(jù)可以有不同的的數(shù)據(jù)寬度;
執(zhí)行速度更快。

計(jì)算機(jī)結(jié)構(gòu)的基本元素:
中央處理器(CPU)
內(nèi)存儲(chǔ)器
I/O設(shè)備
4.2 什么是操作系統(tǒng)
定義:
計(jì)算機(jī)操作系統(tǒng)是負(fù)責(zé)管理系統(tǒng)硬件,并為上層應(yīng)用提供穩(wěn)定編程接口和人機(jī)交互界面的軟件集合。
最核心的工作:硬件管理與抽象。
肩負(fù)兩大重任:
面向下層:管理硬件(CPU、內(nèi)存、Flash、各種IO設(shè)備)
面向上層:一方面,為用戶提供可用的人機(jī)交互界面;另一方面,負(fù)責(zé)為第三方程序的研發(fā)提供便捷、可靠、高效的API。
操作系統(tǒng)的難點(diǎn):進(jìn)程和內(nèi)存管理、硬件驅(qū)動(dòng)的支持等,這正是Linux的長(zhǎng)處所在。
4.3 進(jìn)程間通信的經(jīng)典實(shí)現(xiàn)
進(jìn)程間的通信(Inter-process communication,IPC)是指運(yùn)行在不同進(jìn)程(不論是否在同一臺(tái)機(jī)器)中的若干線程間的數(shù)據(jù)交換。
實(shí)現(xiàn)方式:消息傳遞、管道、文件共享、操作系統(tǒng)提供的公共信息機(jī)制等等。
4.3.1 共享內(nèi)存(Shared Memory)
一種常用的IPC機(jī)制,優(yōu)勢(shì):共享內(nèi)存區(qū)域,減少數(shù)據(jù)的復(fù)制操作,速度快。
實(shí)現(xiàn)步驟:
創(chuàng)建內(nèi)存共享區(qū)
映射內(nèi)存共享區(qū)
訪問內(nèi)存共享區(qū)
進(jìn)程間通信
撤銷內(nèi)存映射區(qū)
刪除內(nèi)存共享區(qū)
4.3.2 管道(Pipe)
一種常見的IPC方式
分立管道的兩邊,進(jìn)行數(shù)據(jù)的傳輸通信
管道是單向的
一根管道同時(shí)具有“讀取”端(read end)和“寫入”端(write end)
管道有容量限制
4.3.3 UNIX Domain Socket(UDS)
專門針對(duì)單機(jī)內(nèi)的進(jìn)程間通信,有時(shí)稱為IPC Socket。
Network Socket是以TCP/IP協(xié)議棧為基礎(chǔ),UDS因?yàn)槭潜镜貎?nèi)的“安全可靠操作”,實(shí)現(xiàn)機(jī)制上并不依賴于這些協(xié)議。
典型流程:

UDS的基本流程與傳統(tǒng)Socket一致,只是在參數(shù)上有區(qū)分:
服務(wù)器端監(jiān)聽I(yíng)PC請(qǐng)求;
客戶端發(fā)起IPC申請(qǐng);
雙方成功建立起IPC連接;
客戶端向服務(wù)端發(fā)送數(shù)據(jù),證明IPC通信是有效的
4.3.4 Remote Procedure Calls(RPC)
涉及的通信雙方通常運(yùn)行于兩臺(tái)不同的機(jī)器中。

4.4 同步機(jī)制的經(jīng)典實(shí)現(xiàn)
同步:如果多個(gè)進(jìn)程間存在時(shí)序關(guān)系,需要協(xié)同工作以完成一項(xiàng)任務(wù)
互斥:如果多個(gè)進(jìn)程并不滿足協(xié)同的條件,而只是因?yàn)楣蚕砭哂信潘缘馁Y源時(shí)所產(chǎn)生的關(guān)系。
4.4.1 信號(hào)量(Semaphore)
涉及的元素:信號(hào)量(S)、PV原語操作(有時(shí)稱wait()、signal())。
S:共享資源的可用數(shù)量
P: 減少S的計(jì)數(shù)(進(jìn)入共享區(qū)的操作)
V:增加S的計(jì)數(shù)(退出共享區(qū)的操作)

4.4.2 Mutex
是Mutual Exclusion的縮寫,即互斥體
4.4.3 管程(Monitor)
一種控制更為簡(jiǎn)單的同步手段。
可以被多個(gè)進(jìn)程/線程安全訪問的對(duì)象(object)或模塊(module)。
具備安全性、互斥性、共享性。
4.4.4 Linux Futex
核心優(yōu)勢(shì)是Fast。
4.4.5 同步范例
生產(chǎn)者與消費(fèi)者問題:
兩個(gè)進(jìn)程共享一塊大小為N的緩沖區(qū),其中一個(gè)進(jìn)程負(fù)責(zé)填充數(shù)據(jù)(生產(chǎn)者),另一個(gè)進(jìn)程負(fù)責(zé)讀取數(shù)據(jù)(消費(fèi)者)。
問題的核心有兩點(diǎn):
當(dāng)緩沖區(qū)滿時(shí),禁止生產(chǎn)者繼續(xù)添加數(shù)據(jù),直到消費(fèi)者讀取了部分?jǐn)?shù)據(jù);
當(dāng)緩沖區(qū)空時(shí),消費(fèi)者應(yīng)等待對(duì)方繼續(xù)生產(chǎn)后再執(zhí)行操作。
解決方式:信用量,用到3個(gè)Semaphore,功能如下:
S_emptyCount: 用于生產(chǎn)者獲取可用的的緩沖空間大小,初始N
S_fillCount: 用于消費(fèi)者獲取可用的數(shù)據(jù)大小,初始為0
S_mutex: 用于操作緩沖區(qū),初始為1
生產(chǎn)者的執(zhí)行步驟:
循環(huán)開始;
Produce_item;
P(S_emptyCount)
P(S_mutex)
Put_item_to_buffer
V(S_mutex)
V(S_fillCount)
繼續(xù)循環(huán)
消費(fèi)者的執(zhí)行步驟:
循環(huán)開始
P(S_fillCount)
P(S_mutex)
Read_item_from_buffer
V(S_mutex)
V(S_emptyCount)
Consume
繼續(xù)循環(huán)
4.5 Android中的同步機(jī)制
4.5.1 進(jìn)程間同步 - Mutex
頭文件:frameworks/native/include/utils/Mutex.h
既可以處理進(jìn)程內(nèi)同步、又可以解決進(jìn)程間同步。
4.5.2 條件判斷 - Condition
頭文件:frameworks/native/include/utils/Condition.h
核心思想:判斷“條件是否已經(jīng)滿足”,如果滿足則馬上返回,繼續(xù)執(zhí)行未完成的動(dòng)作,否則就進(jìn)行休眠等待,直到條件滿足時(shí)有人喚醒它。
4.5.3 “柵欄、障礙” - Barrier
頭文件:frameworks/native/services/surfaceflinger/Barrier.h
Barrier是填充了“具體條件”的Condition,專門為SurfaceFlinger而設(shè)計(jì)。
通常被用于對(duì)某線程是否初始化完成進(jìn)行判斷,這種場(chǎng)景具有不可逆性。
4.5.4 加解鎖的自動(dòng)化操作 - Autolock
在Mutex類內(nèi)部的嵌套類Autolock,實(shí)現(xiàn)加、解鎖的自動(dòng)化操作。
當(dāng)Auto構(gòu)造時(shí),會(huì)主動(dòng)調(diào)用內(nèi)部成員變量mLock的lock()方法獲取一個(gè)鎖。
而析構(gòu)時(shí)正好相反,調(diào)用它的unlock()方法釋放鎖。
4.5.5 讀寫鎖 - ReaderWriterMutex
基礎(chǔ)仍是mutex,特點(diǎn)是 允許有多個(gè)對(duì)象共享Read鎖,但同時(shí)卻只能有唯一一個(gè)對(duì)象擁有Write鎖。
4.6 操作系統(tǒng)內(nèi)存管理基礎(chǔ)
內(nèi)存管理是操作系統(tǒng)的重點(diǎn)和難點(diǎn)
內(nèi)存管理重點(diǎn)理解幾個(gè)核心:虛擬內(nèi)存、內(nèi)存分配與回收、內(nèi)存保存。
4.6.1 虛擬內(nèi)存(Virtual Memory)
虛擬內(nèi)存:為大體積程序的運(yùn)行提供了可能。
基本思想:
將外存儲(chǔ)器的部分空間作為內(nèi)存的擴(kuò)展
當(dāng)內(nèi)存資源不足時(shí),系統(tǒng)將按照一定算法自動(dòng)挑選優(yōu)先級(jí)低的數(shù)據(jù)塊,并把它們存儲(chǔ)到硬盤中。
后續(xù)如果需要用到硬盤中的這些數(shù)據(jù)塊,系統(tǒng)將產(chǎn)生“缺頁”指令,然后把它們交換回內(nèi)存中。
這些操作是由操作系統(tǒng)內(nèi)部?jī)?nèi)核自動(dòng)完成,對(duì)上層應(yīng)用“完全透明”。
涉及3種不同的地址空間:
1、邏輯地址
是程序編譯后所產(chǎn)生的地址,Segment Selector(段選擇子, 16bit) + Offset (偏移值,32bit)
2、線性地址
是邏輯地址經(jīng)過分段機(jī)制轉(zhuǎn)換后形成的
3、物理地址
是指機(jī)器真實(shí)的物理內(nèi)存所能表示的地址空間范圍,64KB內(nèi)存的物理地址范圍是 0x0000 - 0xFFFF

4.6.2 內(nèi)存保護(hù)(Memory Protection)
4.6.3 內(nèi)存分配與回收
分Native層(C/C++)、Java層
4.6.4 進(jìn)程間通信 - mmap
IPC方式: 通過映射同一塊物理內(nèi)存來共享內(nèi)存,減少數(shù)據(jù)復(fù)制次數(shù),提高效率。
mmap可以將某個(gè)設(shè)備或者文件映射到應(yīng)用進(jìn)程的內(nèi)存空間中,這樣訪問這塊內(nèi)存就相當(dāng)于對(duì)設(shè)備/文件進(jìn)行讀寫,而不需要通過read()、write()。
4.6.5 寫時(shí)拷貝技術(shù)(Copy on Write)
基本思想:多個(gè)對(duì)象在起始時(shí)共享某些資源(如代碼段、數(shù)據(jù)段),直到某個(gè)對(duì)象需要修改該資源才擁有自己的一份拷貝。
4.7 Android中的Low Memory Killer
Linux底層內(nèi)核的內(nèi)存監(jiān)控機(jī)制:OOMKiller,核心思想:按照優(yōu)先級(jí)順序,從低到高逐步殺掉進(jìn)程,回收內(nèi)存。
優(yōu)先級(jí)的設(shè)定策略需綜合以下幾個(gè)因素:
進(jìn)程消耗的內(nèi)存
進(jìn)程占用的CPU時(shí)間
oom_adj(OOM權(quán)重)
Android擴(kuò)展出自己的內(nèi)存監(jiān)控體系,Linux的“內(nèi)存殺手”要等到系統(tǒng)資源“瀕臨絕境”的情況下才產(chǎn)生效果,而Android則實(shí)現(xiàn)了“不同梯級(jí)”的Killer(Low Memory Killer(LMK))。
LMK的源碼在內(nèi)核工程的driver/staging/android/Lowmemorykiller.c中。
4.8 Android匿名共享內(nèi)存(Anonymous Shared Memory)
Anonymous Shared Memory(簡(jiǎn)稱Ashmem)是Android特有的內(nèi)存共享機(jī)制,可以將制定的物理內(nèi)存分別映射到各個(gè)進(jìn)程自己的虛擬地址空間中,從而便捷地實(shí)現(xiàn)進(jìn)程間的內(nèi)存共享。
應(yīng)用實(shí)例:基于ashmem設(shè)備來實(shí)現(xiàn)跨進(jìn)程內(nèi)存共享,如MemoryDealer。
匿名共享內(nèi)存涉及設(shè)備驅(qū)動(dòng)、Binder原理等一系列技術(shù),比較難理解,等學(xué)習(xí)相關(guān)基礎(chǔ)知識(shí),再來攻克。
4.9 JNI
JNI(Java Native Interface)是一種允許運(yùn)行于JVM的Java程序去調(diào)用(反向亦然)本地代碼的編程框架。
有3種情況需要用到JNI:
應(yīng)用程序需要一些平臺(tái)相關(guān)的feature的支持,而Java無法滿足
兼容以前的用其他語言書寫的代碼庫
應(yīng)用程序的某些關(guān)鍵操作對(duì)運(yùn)行速度要求較高。
JNI涉及以下兩方面:
Java Code -> Native Code
Native Code -> Java Code
4.9.1 Java函數(shù)的本地實(shí)現(xiàn)
創(chuàng)建一個(gè)可供Java代碼調(diào)用的本地函數(shù)步驟:
將需要本地實(shí)現(xiàn)的Java方法加上native聲明;
使用javac命令編譯Java類
使用javah生成.h頭文件
在本地代碼中實(shí)現(xiàn)native方法
編譯上述的本地方法,生成動(dòng)態(tài)鏈接庫
在Java類中加載這一動(dòng)態(tài)鏈接庫
Java代碼中其他地方可以正常調(diào)用這個(gè)native方法
4.9.2 本地代碼訪問JVM
上節(jié)內(nèi)容的“逆向”操作,本地層(C/C++)訪問JVM空間(Java)。
4.10 Java中的反射機(jī)制
4.11 學(xué)習(xí)Android系統(tǒng)的兩條線索
主線:操作系統(tǒng)的體系結(jié)構(gòu)、硬件組成
輔線:在主線的基礎(chǔ)上,以Android系統(tǒng)的5層框架為輔,逐一解析各層框架中的重要元素,或拾級(jí)而上,或深入淺出,直到問題的最根源處。