一、iOS程序內存分爲幾個區
iOS內存分爲5大區域
1. 棧區:編譯器自動分配並釋放,存放函數的參數值,局部變量等。棧是系統數據結構,對應線程/進程是唯一的。
2. 堆區:由程序員分配和釋放,如果程序員不釋放,程序結束時,可能會由操作系統回收 ,比如在iOS
中 alloc
都是存放在堆中。
3. 全局區:全局變量和靜態變量的存儲是放在一起的,初始化的全局變量和靜態變量存放在一塊區域,未初始化的全局變量和靜態變量在相鄰的另一塊區域,程序結束後由系統釋放。
4. 文字常量區:存放常量字符串,程序結束後由系統釋放程序結束釋放。
5. 代碼區:存放函數的二進制代碼
二、iOS程序內存的每個分區怎麼存儲(舉例說明)
- 棧區:存放的局部變量、先進後出、一旦出了作用域就會被銷燬;函數跳轉地址,現場保護等,內存地址從高到低分配。
-
堆區:堆區的地址是從低到高分配,通過程序員通過
alloc
手動分配。 - 全局區:包含兩個部分,未初始化區,初始化區域。全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域;
代碼區存放於低地址,棧區存放於高地址。區與區之間並不是連續的。堆區的內存是應用程序共享的,堆中的內存分配是系統負責的;當引用計數爲0的時候,系統會回收該內存。
三、block一般存在哪裏(分ARC和MRC)
- 在
MRC
下,Block
默認是分配在棧上的,除非進行顯式執行的copy
方法,只要block沒有引用外部的局部變量,block
放在全局區裏面 - 在
ARC
的中,對象默認是用__strong
修飾的,所以大部分情況下編譯器都會將block
從棧自動複製到堆上。有一個特殊情況,如果僅僅定義了block
沒有賦值給變量的話,仍是在棧上。這種情況下隨着作用域結束,block
將會銷燬回收。
四、代碼區存儲的是什麼?
代碼區存放的是程序中函數編譯後的CPU
指令
五、進程和線程的理解(從資源分配進行理解)
進程和線程都是由操作系統所體會的程序運行的基本單元,系統利用該基本單元實現系統對應用的併發性
1. 一個程序至少有一個進程,一個進程至少有一個線程。
2. 線程的劃分尺度小於進程,使得多線程程序的併發性高。
線程是進程的一個實體,是CPU
調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。
六、進程線程的內存分配和管理
當程序被運行時,需要將可執行文件加載到內存,在內存中的可執行文件形成進程,一個進程(文件)可以同時存在多個進程(內存)
運行程序的時候,需要將可執行文件加載到內存中,形成進程。每個進程佔據了一塊獨立的內存區域,這塊內存區域又劃分成不同的區域,從低地址到高地址依次爲:代碼區、只讀常量區、全局區/數據區、BSS段、堆區、棧區 。
7、多線程中哪些內存是共享哪些獨佔
多線程中,線程之間有共享資源和獨佔資源。
共享資源有:
1. 進程申請的堆內存
2. 進程打開的文件描述符
3. 進程的全局數據
4. 進程id,進程組id
5. 進程目錄
6. 信號處理器
獨佔資源有:
1. 線程ID
2. 寄存器組的值:每個線程有自己不同的運行線索,當從一個線 程切換到另一個線程上 時,必須將原有的線程的寄存器集合的狀態保存,以便將來該線程在被重新切換到時能得以恢復。
3. 線程堆棧
4. 錯誤返回碼
5. 信號屏蔽碼
6. 線程的優先級
八、實現多線程同步的方式
同步方式有互斥鎖(mutex
),條件變量(condition variable
)和讀寫鎖(reader-writer lock
)來同步資源
iOS 互斥鎖有@synchronized
條件信號量dispatch_semaphore_t
NSConditionLock
讀寫鎖 pthread_rwlock
九、兩個異步子線程輸出字符串,主線程前後也輸出一個字符串,順序如何,爲什麼是這樣的?
先執行主線程種操作,在執行一步子線程操作,子線程在分配時遵循,新建,就續,運行,阻塞,死亡這個生命週期,而主線程已經運行狀態,所以會先運行主線程的操作,操作遵循FIFO的模式進行。子線程如果沒有特殊的優先級指定,默認處於同一優先級,所以也遵循FIFO的模式運行。
十、任務A,B,C先執行A和B再執行C可以怎麼實現(group,條件鎖,barrier)
1. group
通過創建信號量訪問資源數量爲1,然後通過wait
和sign
順序執行group
內線程。
2. NSConditionLock
,通過控制創建條件和解鎖條件,順序執行線程。
let lock = NSConditionLock.init(condition: 3)
DispatchQueue.global().async {
lock.lock(whenCondition: 3)
print("A")
lock.unlock(withCondition: 2)
}
DispatchQueue.global().async {
lock.lock(whenCondition: 2)
print("B")
lock.unlock(withCondition: 1)
}
DispatchQueue.global().async {
lock.lock(whenCondition: 1)
print("C")
lock.unlock()
}
3. barrier
允許在一個併發隊列中創建一個同步點。當在併發隊列中遇到一個barrier
, 他會延遲執行barrier
的block
,等待所有在barrier
之前提交的blocks
執行結束。 這時,barrier block
自己開始執行。
十一、屬性的修飾關鍵詞有哪些
十二、atomic
和nonatomic
的區別,如果是你覺得該怎麼實現atomic
一樣的效果
主要區別在於atomic
保證 get
、set
操作的完整性。
可以堆get
,set
操作加鎖,實現atomic
一樣的功能。
十三、atomic
一定是線程安全的嗎?什麼情況下是不安全的?
不一定是線程安全的,只保證了get
,set
操作安全,但是不保證資源線程的安全。
如果一個線程正在getter
或者 setter
時,有另外一個線程同時對該屬性進行release
操作,如果release
先完成,會造成crash
十四、copy
常用來修飾什麼,爲什麼?
常常用來修飾NSString
,使用copy
修飾之後,即使屬性拷貝來自可變字符串,也會被深拷貝成不可變字符串,也就是源字符串修改之後不會影響到屬性字符串,增強了代碼的健壯性。
十五、weak
和assign
的區別
十六、delegate
你一般用什麼修飾(回答weak
,爲什麼?可以用assign
嗎)
十七、循環引用(weak
,用assign
修飾block
可以嗎)
十八、KVO
的實現原理(runtime
)或者你要實現KVO
你會怎麼做
KVO
運用了一個isa-swizzling
技術,isa-swizzling
就是混合指針機制,將2個對象的isa
指針互相調換。
當某個類的屬性對象第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的 setter
方法。派生類在被重寫的setter
方法內實現真正的通知機制。
每個類對象中都有一個isa
指針指向當前類,當一個類對象的第一次被觀察,那麼系統會偷偷將isa
指針指向動態生成的派生類,從而在給被監控屬性賦值時執行的是派生類的setter
方法
鍵值觀察通知依賴於NSObject
的兩個方法: willChangeValueForKey:
和 didChangevlueForKey:
在一個被觀察屬性發生改變之前, willChangeValueForKey:
一定會被調用,這就 會記錄舊的值。而當改變發生後,didChangeValueForKey:
會被調用,繼而 observeValueForKey:ofObject:change:context:
也會被調用。
十九、旋轉數組找最小數(算法)
思路:
- 從頭到尾遍歷數組一次,就能找出最小的元素,時間複雜度顯然是
O(n)
。 - 通過二分查找的方式,時間複雜度爲
O(logn)
觀察一下數組的特性,首先遞增(稱爲遞增a
),然後突然下降到最小值,然後再遞增(稱爲遞增b
)。當然還有一種特殊情況,就是數組遞增,中間沒有下降,即旋轉元素個數爲0
。對於一般的情況,假設A
爲輸入數組,left
和right
爲數組左右邊界的座標,考察中間位置的值A[mid]
,如果A[mid] <= A[right]
,表明處於遞增b,調整右邊界right = mid
;如果A[mid] >= A[left]
,表明處於遞增a
,因此調整左邊界left = mid
。當左右邊界相鄰時,較小的一個就是數組的最小值。其實,對於一般情況,右邊界所指的元素爲最小值。對於特殊情況,即旋轉個數爲0
。按照上述算法,右邊界會不斷減少,直到與左邊界相鄰。這時左邊界所指的元素爲最小值。
//# Swift 實現
func findMin( pArray:[Int]) -> Int{
let len = pArray.count
if len <= 0 { return 0 };
var left:Int = 0
var right:Int = len - 1
var mid:Int = 0
while(right - left != 1)
{
mid = left + ((right - left)>>1);
if pArray[right] >= pArray[mid] {
right = mid;
} else if pArray[left] <= pArray[mid] {
left = mid
}
}
return pArray[right] > pArray[left] ? pArray[left] : pArray[right]
}
推薦文集
收錄:原文地址