萬點五實現2

堆分區

image
  • 堆大小 = 新生代 + 老年代。默認下,新生代 ( Young ) = 1/3 的堆空間大小,老年代 ( Old ) = 2/3 的堆空間大小;

  • 新生代 ( Young ) 被細分為 Eden 和 兩個 Survivor 區域,這兩個 Survivor 區域分別被命名為 from 和 to,以示區分。默認的,Edem : from : to = 8 : 1 : 1;

  • JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來為對象服務,所以無論什么時候,總是有一塊 Survivor 區域是空閑著的。因此,新生代實際可用的內存空間為 9/10 ( 即90% )的新生代空間;

  • GC 分為兩種:老生代中采用標記-清除算法的Full GC ( 或稱為 Major GC )和新生代中采用復制算法的Minor GC。新生代是 GC 收集垃圾的頻繁區域;

  • 持久代位于方法區,且僅存在于Hotspot虛擬機中,sun公司計劃移除。

**所謂的新生代和老年代是針對于分代收集算法來定義的,新生代又分為Eden和Survivor兩個區。加上老年代就這三個區。數據會首先分配到Eden區 當中(當然也有特殊情況,如果是大對象那么會直接放入到老年代(大對象是指需要大量連續內存空間的java對象)。),當Eden沒有足夠空間的時候就會 觸發jvm發起一次Minor GC。如果對象經過一次Minor GC還存活,并且又能被Survivor空間接受,那么將被移動到Survivor空 間當中。并將其年齡設為1,對象在Survivor每熬過一次Minor GC,年齡就加1,當年齡達到一定的程度(默認為15)時,就會被晉升到老年代 中了,當然晉升老年代的年齡是可以設置的。

其實新生代和老年代就是針對于對象做分區存儲,更便于回收等等**

新生代主要存放的是那些很快就會被GC回收掉的或者不是特別大的對象(這個大就要看你是否設置了-XX:PretenureSizeThreshold 參數了)。新生代采用的復制算法,即將新生代分為3個區:較大的Eden和兩個較小的Survivor(默認的Eden:Survivor = 8:1)。發生在新生代的GC為Minor GC 。在Minor GC時會將新生代中還存活著的對象復制進一個Survivor中,然后對Eden和另一個Survivor進行清理。所以,平常可用的新生代大小為Eden的大小+一個Survivor的大小年代則是存放那些在程序中經歷了好幾次回收仍然還活著或者特別大的對象(這個大就要看你是否設置了-XX:PretenureSizeThreshold 參數了)。老年代采用的是標記-清除或者標記-整理算法,這兩個算法主要看虛擬機采用的哪個收集器,兩種算法的區別是:標記-清除可能會產生大量連續的內存碎片。在老年代中的GC則為Major GC。Major GC和Full GC會造成stop-the-world。-Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256mXms,即為jvm啟動時得JVM初始堆大小,Xmx為jvm的最大堆大小,xmn為新生代的大小,permsize為永久代的初始大小,MaxPermSize為永久代的最大空間。老年代和新生代也是和內存相關,虛擬機初始化時已經設定了使用的內存大小,并劃分為三部分:新生代– 新創建的對象,舊生代 – 經過多次垃圾回收沒有被回收的對象或者大對象持久代– JVM使用的內存,包含類信息等所謂的新生代和老年代是針對于分代收集算法來定義的,新生代又分為Eden和Survivor兩個區。加上老年代就這三個區。數據會首先分配到Eden區 當中(當然也有特殊情況,如果是大對象那么會直接放入到老年代(大對象是指需要大量連續內存空間的java對象)。),當Eden沒有足夠空間的時候就會 觸發jvm發起一次Minor GC。如果對象經過一次Minor GC還存活,并且又能被Survivor空間接受,那么將被移動到Survivor空 間當中。并將其年齡設為1,對象在Survivor每熬過一次Minor GC,年齡就加1,當年齡達到一定的程度(默認為15)時,就會被晉升到老年代 中了,當然晉升老年代的年齡是可以設置的。其實新生代和老年代就是針對于對象做分區存儲,更便于回收等等

  • 當對象在 Eden ( 包括一個 Survivor 區域,這里假設是 from 區域 ) 出生后,在經過一次 Minor GC 后,如果對象還存活,并且能夠被另外一塊 Survivor 區域所容納( 上面已經假設為 from 區域,這里應為 to 區域,即 to 區域有足夠的內存空間來存儲 Eden 和 from 區域中存活的對象 ),則使用復制算法將這些仍然還存活的對象復制到另外一塊 Survivor 區域 ( 即 to 區域 ) 中,然后清理所使用過的 Eden 以及 Survivor 區域 ( 即 from 區域 ),并且將這些對象的年齡設置為1,以后對象在 Survivor 區每熬過一次 Minor GC,就將對象的年齡 + 1,當對象的年齡達到某個值時 ( 默認是 15 歲,可以通過參數 -XX:MaxTenuringThreshold 來設定 ),這些對象就會成為老年代。但這也不是一定的,對于一些較大的對象 ( 即需要分配一塊較大的連續內存空間 ) 則是直接進入到老年代;

  • Full GC 發生的次數不會有 Minor GC 那么頻繁,并且做一次 Full GC 要比進行一次 Minor GC 的時間更長;

  • 因為 jvm 每次只是用新生代中的 eden 和 一個 survivor,因此新生代實際的可用內存空間大小為所指定的 90%;

  • PermGen 即永久代 ( 方法區 ),它還有一個名字,叫非堆,主要用來存儲由 jvm 加載的類文件信息、常量、靜態變量等;

  • 每次調 System.gc(),是先進行 Minor GC,然后再進行 Full GC;

  • 當 Full GC 進行的時候,默認的方式是盡量清空新生代 ( YoungGen ),因此在調 System.gc() 時,新生代 ( YoungGen ) 中存活的對象會提前進入老年代;

題眼:JVM使用的是分代垃圾回收的方式,可以將Java對象分為"年輕"對象和"年老"對象.JVM將內存堆(Heap)分為兩個區域,一個是"年輕"區,另一個是"老"區,Java將這兩個區域分別稱作是"新生代"和"老生代"。

詳細:JVM使用的是分代垃圾回收的方式,主要是因為在程序運行的時候會有如下特點:

◆大多數對象在創建后很快就沒有對象使用它了。

◆大多數在一直被使用的對象很少再去引用新創建的對象。因此就將Java對象分為"年輕"對象和"年老"對象,JVM將內存堆(Heap)分為兩個區域,一個放年輕對象,一個放年老對象,java對對內存的這兩個區域分別成為 新生代,老生代。

新生代區域特點: a) 絕大多數新創建的對象都存放在這個區域b) 此區域一般來說較小而且JVM垃圾回收頻率較高c) 采用的算法和存放對象特點使得該區域JVM垃圾回收的效率也非常高

老生代區域特點: a) 將在"新生代"中生存了較長時間的對象轉移過來b) 區域一般要大一些而且增長的速度相對于"新生代"要慢一些c) 垃圾回收的執行頻率也會低很多

了解這個對于我們的好處是:JVM在JVM垃圾回收處理時會消耗一定的系統資源,如果我們在JVM啟動的時候添加相關參數來控制"新生代"區域的大小以達到調整JVM垃圾回收處理的頻率,那么我們就會合理利用系統資源。

補充:

1 通過設置-xx:PretenureSizeThreshold 來設置多大的對象直接進入老年代。你把這個值調的大一點,則可以保證大部分對象不會直接進入老年代,老年代對象的gc同長慢,一般內存不滿時不會gc的,所以你的大對象一直都在不會被回收。2 (-xx:MaxTenuringThreshold默認15)這個值也可以調調,這個表示在新生代折騰多少次后進入年老代。


安卓系統機制

系統啟動過程

  1. 加載bootloader

  2. Bootloader加載Linux內核

    Bootloader作用是:類似于BIOS,初始化基本硬件設備,建立內存空間映射、為加載linux內核準備好運行環境。Linux內核初始化完成后,裝載完文件系統,就啟動了第一個init進程

  3. Linux初始化后啟動第一個進程init

    init進程解析linux的腳本文件init.rc,根據這個文件內容init進程會裝載Android文件系統,創建系統目錄,啟動Android重要守護進程等。

    init進程還會分裂出更多的名為damens的守護進程,如usb deamon等處理底層硬件相關

  4. init進程初始化結束后會啟動Zygote進程。

    • Zygote進程

    Zygote進程fork出應用進程,是所有進程的父進程。

    Zygote進程初始化的時候回創建Dalvik虛擬機,預裝載系統資源文件和java類,所有從Zygote fork出的進程繼承和共享這些資源不用浪費時間重新加載。

    Zygote初始化完后,也將變成守護進程,負責響應啟動apk應用的啟動請求。

  5. Zygote進程fork第一個進程SystemServer進程

    SystemServer進程是Zygote fork出的第一個進程,也是整個Android系統的核心進程。在SystemServer主要運行的是Binder服務。

    SystemServer首先啟動本地服務SensorService接著啟動ActivityManagerService、WindowsManagerService、PackageManagerService等所有java服務。

  6. SystemService加載完所有java服務后調用AMS的SystemReady()方法

    其實是為了打開Launcher。還要去PMS取一下所有類型為ACTION_MAIN的intent決定打開的Launcher。

App啟動流程

  1. 點擊app圖標后,click事件會調用startActivity(intent)會通過Binder IPC機制最終調用到AMS。該服務會執行以下操作:

    1. 通過PackageManager的resolveIntent()獲得該intent對象的指向信息

    2. 通過PMS獲得用戶是否有權限調用該intent指向的Activity

    3. 如果有權限,AMS會檢查并在新的task中啟動目標activity

      檢查該進程的ProcessRecord是否存在,如果ProcessRecord為null,AMS會創建新的進程并實例化目標activity

  2. 創建進程

    AMS調用startProcessLocked()創建新的進程,該方法會通過Socket通道傳參給Zygote進程,Zygote孵化自己并調用ZYgoteinit.main()方法來實例化ActivityThread對象并最終返回新進程的PID。

    ActivityThread隨后依次調用Looper.prepare() 和Looper.loop()開啟消息循環

  3. 綁定進程到Application

    通過ActivityThread調用bindApplication()完成。

    該方法發送一個BIND_APPLICATION消息到消息隊列,最終通過handleBindApplication()處理該消息,最終調用makeApplication()方法來加載App的classes到內存。

  4. 啟動Activity

    到這里,系統已經擁有該Application的進程。后面調用的順序就是普通的從一個已經存在的進程啟動一個新進程的Activity

    實際步驟是:執行realStartActivity(),他會調用application線程的sheduleLauncherActivity()發生一個LAUNCHER_ACTIVITY消息到消息隊列中,通過handleLauncherActivity()處理該消息。

安裝軟件過程

apk文件就是一個資源和組件的壓縮包,安裝的過程就是復制和解析的過程。

  1. 復制
    1. 安卓機有內部存儲和SD卡兩部分很多安卓機的內存并不大需要把apk安裝到SD卡上節省內存空間所以程序目錄/data/app/實際上也是在內部存儲和SD卡上各一個。

    2. 系統自帶的App是安裝在/system/app/目錄下的這個目錄只有root權限才能訪問所以系統App在root之前是無法刪除和修改的也就是說系統App升級時實際上是在/data/app/里重新安裝了一個App這個路徑會重新注冊到系統那里系統再打開App時就會指向新App的地址。當然這個新的App是可以卸載的不過新的App卸載后系統會把 /system/app/里那個舊的App提供給你所以是卸掉新的還你舊的。

    3. 還是系統App在root后我們可以操作/system/app/目錄但是系統安裝Apk仍然會裝到/data/app/里所以如果想修改/system/app/目錄里的app必須自己手動push新的apk文件進去這個新的apk文件不會自動被安裝需要重啟設備系統在重啟時檢查到apk被更新才會去安裝apk。

    4. 系統目錄有個/system/priv-app/目錄這里面放的是權限更高的系統核心應用如開機launcher、系統UI、系統設置等這個目錄我們最好不要動保持系統干凈簡潔。

  2. 安裝

    具體的apk安裝過程就是由這個PMS操作的。PMS會監控/data/app/這個目錄在上一步中系統安裝程序向這個目錄復制了一個apkPMS自己就會定期掃描這個目錄找到后綴為apk的文件如果這個apk沒有被安裝過它就會自動開始安裝安裝時會做這么幾件事

    1. 創建應用目錄路徑為/data/data/your package(你的應用包名)App中使用的數據庫、so庫、xml文件等都會放在這個目錄下。

    2. 提取dex文件dex是App的可執行文件系統解壓apk就能得到dex文件然后把dex文件放到/data/dalvik-cache這樣可以提前緩存dex到內存中能加快啟動速度。系統還會把dex優化為odex進一步加快啟動速度。

    3. 判斷是否可以安裝apk如檢查apk簽名等。

    4. 為應用分配并保存一個UIDUID是來自Linux的用戶賬戶體系不過在Android這種單用戶系統里UID被用來與App對應這也是安全機制的一部分每個App都有自己對應的UID這種對應關系是持久化保存的App更新或卸載重裝后系統還會給它分配原來那個UID。用adb pull /data/system/packages.list可以查看所有App的UID。GID(用戶組)一般等于UID。

    5. 利用AndroidManifest文件注冊Apk的各項信息包括但不限于:****. 根據installLocation屬性(internalOnly、auto、preferExternal)選擇安裝在內部存儲器還是SD卡上。. 根據sharedUserId屬性為App分配UID如果兩個App使用同一個UID打包時又使用了相同的簽名它們就被視為同一個用戶可以共享數據甚至運行在同一個進程上。. 向/data/system/packages.xml文件中記錄App的包名、權限、版本號、安裝路徑等;同時在/data/system/packages.list中更新所有已安裝的app列表。. 注冊App中的的四大組件(Activity、Service、Broadcast Receiver和Content Provider)包括組件的intent-filter和permission等。. 在桌面上添加App的快捷方式如果AndroidManifest文件中有多個Activity被標注為<action android:name="android.intent.action.MAIN" />和<category android:name="android.intent.category.LAUNCHER" />系統就會向桌面添加多個App快捷方式所以有時候在安裝一個App后用戶可能會感覺安裝了多個App。

  3. 通知

    apk安裝完成后PMS會發一個ACTION_PACKAGE_ADDED廣播如果是卸載會發ACTION_PACKAGE_REMOVED廣播。

安卓進程機制

  • 前臺進程

  • 可見進程

  • 服務進程

即Service服務

  • 后臺進程

即當前App按Home鍵后成為后臺進程


Binder IPC機制

  • Android 從下而上分了內核層、硬件抽象層、系統服務層、Binder IPC 層、應用程序框架層

  • Android 中「應用程序框架層」以 SDK 的形式開放給開發者使用「系統服務層」中的核心服務隨系統啟動而運行通過應用層序框架層提供的 Manager 實時為應用程序提供服務調用。系統服務層中每一個服務運行在自己獨立的進程空間中應用程序框架層中的 Manager 通過 Binder IPC 的方式調用系統服務層中的服務。

小結

  • Binder IPC 屬于 C/S 架構包括 Client、Driver、Server 三個部分

  • Client 可以手動調用 Driver 的 transact 接口也可以通過 AIDL 生成的 Proxy 調用

  • Server 中會啟動一個「線程池」來處理 Client 的調用請求處理完成后將結果返回給 DriverDriver 再返回給 Client

AIDL

  • 一個繼承了 Binder一個繼承了 AIDL 自動生成的 Stub 對象

  • AIDL 自動生成了 Stub 類

  • 在 Service 端繼承 Stub 類Stub 類中實現了 onTransact 方法實現了「解包」的功能

  • 在 Client 端使用 Stub 類的 Proxy 對象該對象實現了「組包」并且調用 transact 的功能


Activity與Service幾種通信

1.Binder2.intent3.廣播


如何保證服務常駐

  1. 黑色保活

    1. 利用不同進程之間廣播喚起

    2. 保證APP不殺死方法

  2. 白色保活

    • 顯示通知
  3. 灰色保活

    啟動一個不顯示通知的前臺服務

    啟動前臺服務:只需要在服務啟動的時候,調用startForeground()方法,在其中傳入一個待顯示的Notification即可。停止前臺服務,需要調用stopForeground()方法。

    去掉前臺服務的通知,行之有效的方法是:

    1. 需要兩個前臺服務,共享同一個Notification ID。
    1. 一個服務啟動完畢之后,馬上停止自己,會去掉通知欄的通知。
    1. 而之前已經借助這個ID保持前臺的服務,依然會處于前臺的狀態不變。
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,283評論 6 530
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,947評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,094評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,485評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,268評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,817評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,906評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,039評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,551評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,502評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,662評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,188評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,907評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,304評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,563評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,255評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,637評論 2 370

推薦閱讀更多精彩內容

  • java基礎volidate、線程生命周期、反射、NIO 內存分區GC、類加載 強弱等引用 基本數據結構 線程池 ...
    RichardLee123閱讀 288評論 0 3
  • 一 、java虛擬機底層結構詳解 我們知道,一個JVM實例的行為不光是它自己的事,還涉及到它的子系統、存儲區域、...
    葡萄喃喃囈語閱讀 1,501評論 0 4
  • JVM架構 當一個程序啟動之前,它的class會被類裝載器裝入方法區(Permanent區),執行引擎讀取方法區的...
    cocohaifang閱讀 1,683評論 0 7
  • 轉載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,380評論 1 56
  • 1 人有不同的性格 主要是指人有相同的情緒時有不同的反應 2 distinction與眾不同的 complex ...
    241王甜雅閱讀 172評論 2 0