1.Java內(nèi)存模型:
Java虛擬機(jī)規(guī)范中將Java運(yùn)行時(shí)數(shù)據(jù)分為六種鼠渺。
1.程序計(jì)數(shù)器:是一個(gè)數(shù)據(jù)結(jié)構(gòu),用于保存當(dāng)前正常執(zhí)行的程序的內(nèi)存地址忌栅。Java虛擬機(jī)的多線程就是通過(guò)線程輪流切換并分配處理器時(shí)間來(lái)實(shí)現(xiàn)的瓶竭,為了線程切換后能恢復(fù)到正確的位置视乐,每條線程都需要一個(gè)獨(dú)立的程序計(jì)數(shù)器男摧,互不影響蔬墩,該區(qū)域?yàn)椤熬€程私有”。
2.Java虛擬機(jī)棧:線程私有的耗拓,與線程生命周期相同拇颅,用于存儲(chǔ)局部變量表,操作棧乔询,方法返回值蔬蕊。局部變量表放著基本數(shù)據(jù)類型,還有對(duì)象的引用哥谷。
3.本地方法棧:跟虛擬機(jī)棧很像,不過(guò)它是為虛擬機(jī)使用到的Native方法服務(wù)麻献。
4.Java堆:所有線程共享的一塊內(nèi)存區(qū)域们妥,對(duì)象實(shí)例幾乎都在這分配內(nèi)存。
5.方法區(qū):各個(gè)線程共享的區(qū)域勉吻,儲(chǔ)存虛擬機(jī)加載的類信息监婶,常量,靜態(tài)變量齿桃,編譯后的代碼惑惶。
6.運(yùn)行時(shí)常量池:代表運(yùn)行時(shí)每個(gè)class文件中的常量表。包括幾種常量:編譯時(shí)的數(shù)字常量短纵、方法或者域的引用带污。
2.“你能不能談?wù)劊琷ava GC是在什么時(shí)候香到,對(duì)什么東西鱼冀,做了什么事情?”
在什么時(shí)候:
1.新生代有一個(gè)Eden區(qū)和兩個(gè)survivor區(qū)悠就,首先將對(duì)象放入Eden區(qū)千绪,如果空間不足就向其中的一個(gè)survivor區(qū)上放,如果仍然放不下就會(huì)引發(fā)一次發(fā)生在新生代的minor GC梗脾,將存活的對(duì)象放入另一個(gè)survivor區(qū)中荸型,然后清空Eden和之前的那個(gè)survivor區(qū)的內(nèi)存。在某次GC過(guò)程中炸茧,如果發(fā)現(xiàn)仍然又放不下的對(duì)象瑞妇,就將這些對(duì)象放入老年代內(nèi)存里去稿静。
2.大對(duì)象以及長(zhǎng)期存活的對(duì)象直接進(jìn)入老年區(qū)。
3.當(dāng)每次執(zhí)行minor GC的時(shí)候應(yīng)該對(duì)要晉升到老年代的對(duì)象進(jìn)行分析踪宠,如果這些馬上要到老年區(qū)的老年對(duì)象的大小超過(guò)了老年區(qū)的剩余大小自赔,那么執(zhí)行一次Full GC以盡可能地獲得老年區(qū)的空間。
對(duì)什么東西:從GC Roots搜索不到柳琢,而且經(jīng)過(guò)一次標(biāo)記清理之后仍沒(méi)有復(fù)活的對(duì)象绍妨。
做什么: 新生代:復(fù)制清理; 老年代:標(biāo)記-清除和標(biāo)記-壓縮算法柬脸; 永久代:存放Java中的類和加載類的類加載器本身他去。
GC Roots都有哪些: 1. 虛擬機(jī)棧中的引用的對(duì)象 2. 方法區(qū)中靜態(tài)屬性引用的對(duì)象,常量引用的對(duì)象 3. 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象倒堕。
3.Synchronized 與Lock都是可重入鎖灾测,同一個(gè)線程再次進(jìn)入同步代碼的時(shí)候.可以使用自己已經(jīng)獲取到的鎖。
Synchronized是悲觀鎖機(jī)制垦巴,獨(dú)占鎖媳搪。而Locks.ReentrantLock是,每次不加鎖而是假設(shè)沒(méi)有沖突而去完成某項(xiàng)操作骤宣,如果因?yàn)闆_突失敗就重試秦爆,直到成功為止。 ReentrantLock適用場(chǎng)景
1)某個(gè)線程在等待一個(gè)鎖的控制權(quán)的這段時(shí)間需要中斷
2)需要分開(kāi)處理一些wait-notify憔披,ReentrantLock里面的Condition應(yīng)用等限,能夠控制notify哪個(gè)線程,鎖可以綁定多個(gè)條件芬膝。
3)具有公平鎖功能望门,每個(gè)到來(lái)的線程都將排隊(duì)等候。
4.說(shuō)明Activity和Service的生命周期锰霜?
5.如何規(guī)避oom?
1.使用更加輕量的數(shù)據(jù)結(jié)構(gòu)
2.避免在Android里面使用Enum
3.減小Bitmap對(duì)象的內(nèi)存占用
4.使用更小的圖片
5.復(fù)用系統(tǒng)自帶的資源
6.注意在ListView/GridView等出現(xiàn)大量重復(fù)子組件的視圖里面對(duì)ConvertView的復(fù)用
7.Bitmap對(duì)象的復(fù)用
8.避免在onDraw方法里面執(zhí)行對(duì)象的創(chuàng)建
9.避免對(duì)象的內(nèi)存泄露(重點(diǎn))
10.考慮使用Application Context而不是Activity Context
11.注意WebView的泄漏(重點(diǎn))
12.資源文件需要選擇合適的文件夾進(jìn)行存放
13.謹(jǐn)慎使用static對(duì)象(重點(diǎn))
14.特別留意單例對(duì)象中不合理的持有
15.珍惜Services資源
16.謹(jǐn)慎使用“抽象”編程
17.謹(jǐn)慎使用依賴注入框架
18..謹(jǐn)慎使用多進(jìn)程
19.Handler的使用(重點(diǎn))
20.強(qiáng)軟弱虛引用的應(yīng)用(重點(diǎn))
22.主線程操作UI筹误,子線程操作數(shù)據(jù)(必填)
6.什么是ANR 如何避免它?
答:ANR:Application Not Responding癣缅。在Android中纫事,活動(dòng)管理器和窗口管理器這兩個(gè)系統(tǒng)服務(wù)負(fù)責(zé)監(jiān)視應(yīng)用程序的響應(yīng),當(dāng)用戶操作的在5s內(nèi)應(yīng)用程序沒(méi)能做出反應(yīng)所灸,BroadcastReceiver在10秒內(nèi)沒(méi)有執(zhí)行完畢丽惶,就會(huì)出現(xiàn)應(yīng)用程序無(wú)響應(yīng)對(duì)話框,這既是ANR爬立。
避免方法:Activity應(yīng)該在它的關(guān)鍵生命周期方法(如onCreate()和onResume())里盡可能少的去做創(chuàng)建操作钾唬。潛在的耗時(shí)操作,例如網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)操作,或者高耗時(shí)的計(jì)算如改變位圖尺寸抡秆,應(yīng)該在子線程里(或者異步方式)來(lái)完成奕巍。主線程應(yīng)該為子線程提供一個(gè)Handler,以便完成時(shí)能夠提交給主線程儒士。
7.請(qǐng)介紹下ContentProvider是如何實(shí)現(xiàn)數(shù)據(jù)共享的的止。
一個(gè)程序可以通過(guò)實(shí)現(xiàn)一個(gè)Content provider的抽象接口將自己的數(shù)據(jù)完全暴露出去,而且Content providers是以類似數(shù)據(jù)庫(kù)中表的方式將數(shù)據(jù)暴露着撩。Content providers存儲(chǔ)和檢索數(shù)據(jù)诅福,通過(guò)它可以讓所有的應(yīng)用程序訪問(wèn)到,這也是應(yīng)用程序之間唯一共享數(shù)據(jù)的方法拖叙。
要想使應(yīng)用程序的數(shù)據(jù)公開(kāi)化氓润,可通過(guò)2種方法:創(chuàng)建一個(gè)屬于你自己的Content provider或者將你的數(shù)據(jù)添加到一個(gè)已經(jīng)存在的Content provider中,前提是有相同數(shù)據(jù)類型并且有寫(xiě)入Content provider的權(quán)限薯鳍。
如何通過(guò)一套標(biāo)準(zhǔn)及統(tǒng)一的接口獲取其他應(yīng)用程序暴露的數(shù)據(jù)咖气?
Android提供了ContentResolver,外界的程序可以通過(guò)ContentResolver接口訪問(wèn)ContentProvider提供的數(shù)據(jù)挖滤。
8.Service和Thread的區(qū)別崩溪?
答:servie是系統(tǒng)的組件,它由系統(tǒng)進(jìn)程托管(servicemanager)斩松;它們之間的通信類似于client和server悯舟,是一種輕量級(jí)的ipc通信,這種通信的載體是binder砸民,它是在linux層交換信息的一種ipc。而thread是由本應(yīng)用程序托管奋救。1). Thread:Thread 是程序執(zhí)行的最小單元岭参,它是分配CPU的基本單位〕⑺遥可以用 Thread 來(lái)執(zhí)行一些異步的操作演侯。
2). Service:Service 是android的一種機(jī)制,當(dāng)它運(yùn)行的時(shí)候如果是Local Service背亥,那么對(duì)應(yīng)的 Service 是運(yùn)行在主進(jìn)程的 main 線程上的秒际。如:onCreate,onStart 這些函數(shù)在被系統(tǒng)調(diào)用的時(shí)候都是在主進(jìn)程的 main 線程上運(yùn)行的狡汉。如果是Remote Service娄徊,那么對(duì)應(yīng)的 Service 則是運(yùn)行在獨(dú)立進(jìn)程的 main 線程上。
既然這樣盾戴,那么我們?yōu)槭裁匆?Service 呢寄锐?其實(shí)這跟 android 的系統(tǒng)機(jī)制有關(guān),我們先拿 Thread 來(lái)說(shuō)。Thread 的運(yùn)行是獨(dú)立于 Activity 的橄仆,也就是說(shuō)當(dāng)一個(gè) Activity 被 finish 之后剩膘,如果你沒(méi)有主動(dòng)停止 Thread 或者 Thread 里的 run 方法沒(méi)有執(zhí)行完畢的話,Thread 也會(huì)一直執(zhí)行盆顾。因此這里會(huì)出現(xiàn)一個(gè)問(wèn)題:當(dāng) Activity 被 finish 之后怠褐,你不再持有該 Thread 的引用。另一方面您宪,你沒(méi)有辦法在不同的 Activity 中對(duì)同一 Thread 進(jìn)行控制奈懒。
舉個(gè)例子:如果你的 Thread 需要不停地隔一段時(shí)間就要連接服務(wù)器做某種同步的話,該 Thread 需要在 Activity 沒(méi)有start的時(shí)候也在運(yùn)行蚕涤。這個(gè)時(shí)候當(dāng)你 start 一個(gè) Activity 就沒(méi)有辦法在該 Activity 里面控制之前創(chuàng)建的 Thread筐赔。因此你便需要?jiǎng)?chuàng)建并啟動(dòng)一個(gè) Service ,在 Service 里面創(chuàng)建揖铜、運(yùn)行并控制該 Thread茴丰,這樣便解決了該問(wèn)題(因?yàn)槿魏?Activity 都可以控制同一 Service,而系統(tǒng)也只會(huì)創(chuàng)建一個(gè)對(duì)應(yīng) Service 的實(shí)例)天吓。
因此你可以把 Service 想象成一種消息服務(wù)贿肩,而你可以在任何有 Context 的地方調(diào)用 Context.startService、Context.stopService龄寞、Context.bindService汰规,Context.unbindService,來(lái)控制它物邑,你也可以在 Service 里注冊(cè) BroadcastReceiver溜哮,在其他地方通過(guò)發(fā)送 broadcast 來(lái)控制它,當(dāng)然這些都是 Thread 做不到的色解。
- AIDL的全稱是什么茂嗓?如何工作?能處理哪些類型的數(shù)據(jù)科阎?
答:全稱是:Android Interface Define Language
在Android中, 每個(gè)應(yīng)用程序都可以有自己的進(jìn)程. 在寫(xiě)UI應(yīng)用的時(shí)候, 經(jīng)常要用到Service. 在不同的進(jìn)程中, 怎樣傳遞對(duì)象呢?顯然, Java中不允許跨進(jìn)程內(nèi)存共享. 因此傳遞對(duì)象, 只能把對(duì)象拆分成操作系統(tǒng)能理解的簡(jiǎn)單形式, 以達(dá)到跨界對(duì)象訪問(wèn)的目的. 在J2EE中,采用RMI的方式, 可以通過(guò)序列化傳遞對(duì)象. 在Android中, 則采用AIDL的方式. 理論上AIDL可以傳遞Bundle,實(shí)際上做起來(lái)卻比較麻煩述吸。
AIDL(AndRoid接口描述語(yǔ)言)是一種借口描述語(yǔ)言; 編譯器可以通過(guò)aidl文件生成一段代碼,通過(guò)預(yù)先定義的接口達(dá)到兩個(gè)進(jìn)程內(nèi)部通信進(jìn)程的目的. 如果需要在一個(gè)Activity中, 訪問(wèn)另一個(gè)Service中的某個(gè)對(duì)象, 需要先將對(duì)象轉(zhuǎn)化成AIDL可識(shí)別的參數(shù)(可能是多個(gè)參數(shù)), 然后使用AIDL來(lái)傳遞這些參數(shù), 在消息的接收端, 使用這些參數(shù)組裝成自己需要的對(duì)象.
AIDL的IPC的機(jī)制和COM或CORBA類似, 是基于接口的锣笨,但它是輕量級(jí)的蝌矛。它使用代理類在客戶端和實(shí)現(xiàn)層間傳遞值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相關(guān)類.; 2. 調(diào)用aidl產(chǎn)生的class.
AIDL的創(chuàng)建方法:
AIDL語(yǔ)法很簡(jiǎn)單,可以用來(lái)聲明一個(gè)帶一個(gè)或多個(gè)方法的接口,也可以傳遞參數(shù)和返回值错英。 由于遠(yuǎn)程調(diào)用的需要, 這些參數(shù)和返回值并不是任何類型.下面是些AIDL支持的數(shù)據(jù)類型:
不需要import聲明的簡(jiǎn)單Java編程語(yǔ)言類型(int,boolean等)
String, CharSequence不需要特殊聲明
List, Map和Parcelables類型, 這些類型內(nèi)所包含的數(shù)據(jù)成員也只能是簡(jiǎn)單數(shù)據(jù)類型, String等其他比支持的類型.
Android dvm的進(jìn)程和Linux的進(jìn)程, 應(yīng)用程序的進(jìn)程是否為同一個(gè)概念
答:DVM指dalivk的虛擬機(jī)入撒。每一個(gè)Android應(yīng)用程序都在它自己的進(jìn)程中運(yùn)行,都擁有一個(gè)獨(dú)立的Dalvik虛擬機(jī)實(shí)例椭岩。而每一個(gè)DVM都是在Linux 中的一個(gè)進(jìn)程衅金,所以說(shuō)可以認(rèn)為是同一個(gè)概念噪伊。