物理內(nèi)存和虛擬內(nèi)存
物理內(nèi)存就是RAM和寄存器(用來存儲(chǔ)計(jì)算單元執(zhí)行指令的中間結(jié)果)凡蚜。連接處理器和RAM或者寄存器和處理器的是地址總線姊途。這個(gè)地址總線的寬度影響物理地址的索引范圍朦乏,因?yàn)榭偩€的寬度決定了一次可以從寄存器或者內(nèi)存中獲取多少個(gè)bit。
通常地址總線和寄存器和RAM有相同的位數(shù),更容易傳輸數(shù)據(jù)芜辕。
一般來說如果要直接讓程序直接訪問存儲(chǔ)器外涧偷,大部分是通過操作系統(tǒng)提供的接口來實(shí)現(xiàn)簸喂。但是在Java不用寫和內(nèi)存相關(guān)的代碼。
我們運(yùn)行程序都要申請(qǐng)內(nèi)存地址燎潮。而通常操作系統(tǒng)管理內(nèi)存是按照進(jìn)程方式處理喻鳄,每個(gè)進(jìn)程都獨(dú)享一個(gè)獨(dú)立的內(nèi)存空間,互不打擾确封,但這個(gè)互不打擾和獨(dú)立性是通過操作系統(tǒng)來保證的除呵。
而這個(gè)獨(dú)立性更多也只是一個(gè)概念性的東西,實(shí)際上物理內(nèi)存可以被多個(gè)運(yùn)行進(jìn)程共享爪喘,這個(gè)稱為虛擬內(nèi)存颜曾。
概念性大概就是計(jì)算機(jī)口頭上是不承認(rèn)自己的物理內(nèi)存是共享的,而表面上看起來也是進(jìn)程內(nèi)存使用相互獨(dú)立的腥放,但是從底層的角度考慮其實(shí)物理內(nèi)存是共享的泛啸。
而完成所謂的邏輯獨(dú)立和實(shí)際不獨(dú)立的方法就是通過虛擬內(nèi)存技術(shù),具體來說是虛擬地址秃症。讓物理內(nèi)存被共享候址,提高內(nèi)存利用,還能拓展內(nèi)存的地址空間种柑。一個(gè)進(jìn)程不活動(dòng)時(shí)候岗仑,會(huì)將這個(gè)進(jìn)程對(duì)應(yīng)的數(shù)據(jù)移動(dòng)到一個(gè)磁盤文件中(通常為windows的頁面文件或者是linux的交換分區(qū)),這樣就騰出內(nèi)存給活動(dòng)程序用啦聚请。當(dāng)我們喚起這個(gè)很久沒使用的程序荠雕,磁盤就開始響稳其,而且會(huì)停頓,將磁盤中的數(shù)據(jù)重新放到物理內(nèi)存中炸卑,這操作很低效率既鞠。
內(nèi)存空間
內(nèi)存空間會(huì)被劃分成內(nèi)核空間和用戶空間,程序只能申請(qǐng)到用戶空間的內(nèi)存盖文,但實(shí)際上程序也能訪問到內(nèi)核空間培漏。
內(nèi)核空間主要適用于操作系統(tǒng)運(yùn)行的程序調(diào)度灶搜,虛擬內(nèi)存使用蝇完,硬件資源連接等程序邏輯咏花。就是給操作系統(tǒng)用的。所以用戶程序不能直接訪問硬件資源疙驾,要通過操作系統(tǒng)發(fā)起凶伙。每一次系統(tǒng)調(diào)用都會(huì)存在內(nèi)存空間的切換,
Java堆
Java堆是用來存儲(chǔ)Java對(duì)象的區(qū)域它碎,堆的大小從JVM啟動(dòng)時(shí)就確定函荣,可以通過-Xmx和-Xms來控制申請(qǐng)大小,但堆的大小申請(qǐng)后就不能改變
線程JVM的運(yùn)行實(shí)體链韭,每個(gè)線程創(chuàng)建時(shí)JVM都會(huì)為它創(chuàng)建一個(gè)堆棧偏竟,
類和類加載器
這兩個(gè)本身就需要存儲(chǔ)空間,他們也被存儲(chǔ)在堆中敞峭,這種區(qū)域叫永久代踊谋?(PermGen區(qū)域)
需要注意JVM按需加載類,只會(huì)加載在應(yīng)用程序指明的類旋讹,一個(gè)類一般而言只會(huì)加載一次殖蚕,倘若你的類加載器是自己實(shí)現(xiàn)的可能會(huì)出現(xiàn)重復(fù)加載的情況,如果PermGen區(qū)不能堆已經(jīng)失效的類做卸載沉迹,可能會(huì)導(dǎo)致PermGen區(qū)內(nèi)存泄漏睦疫。任何系統(tǒng)類或者通過程序類加載器的加載的任何程序類都不能在運(yùn)行時(shí)釋放。
JNI 也會(huì)占用內(nèi)存鞭呕,使得本機(jī)代碼(C語言)可以調(diào)用Java方法
JVM內(nèi)存結(jié)構(gòu)
JVM按照數(shù)據(jù)的存儲(chǔ)結(jié)構(gòu)來劃分內(nèi)存蛤育,將其分成幾種不同格式的數(shù)據(jù),分別存儲(chǔ)在不同的區(qū)域葫松,這些數(shù)據(jù)稱為運(yùn)行時(shí)數(shù)據(jù)瓦糕。
運(yùn)行時(shí)數(shù)據(jù)劃分如下
1.PC寄存器數(shù)據(jù)
2.Java棧
3.堆
4.方法區(qū)
5.本地方法區(qū)
6.運(yùn)行時(shí)常量池
PC寄存器
保存當(dāng)前執(zhí)行程序的內(nèi)存地址,由于Java程序多線程進(jìn)行腋么,所以多線程交叉執(zhí)行時(shí)咕娄,及時(shí)保存下來程序的內(nèi)存地址就很重要了。
Java棧
每創(chuàng)建一個(gè)線程珊擂,JVM就會(huì)為這個(gè)線程創(chuàng)建一個(gè)對(duì)應(yīng)的棧圣勒,這個(gè)棧又會(huì)含有多個(gè)棧幀费变。棧幀和方法相聯(lián)系,每調(diào)用一個(gè)方法就創(chuàng)建了一個(gè)棧幀圣贸。存儲(chǔ)一些內(nèi)部變量挚歧,操作棧,返回值等信息旁趟。
Java棧顧名思義就是棧昼激,它塞的元素是棧幀,在Java棧頂?shù)牡胤讲攀钱?dāng)前執(zhí)行的活動(dòng)棧锡搜,一旦結(jié)束工作就會(huì)返回值然后頂部的棧幀被彈出執(zhí)行下一個(gè)棧幀。Java棧不存在信息共享瞧掺,所以里面的變量不用擔(dān)心同步的問題
堆
存儲(chǔ)Java對(duì)象的地方耕餐,每一個(gè)存儲(chǔ)在堆中的Java對(duì)象都是對(duì)象類的一個(gè)副本,堆是被所有Java線程所共享辟狈,所以應(yīng)該注意同步問題肠缔。
方法區(qū)
用來存儲(chǔ)類結(jié)構(gòu)信息的地方,程序啟動(dòng)一段時(shí)間大小固定哼转。是屬于堆的一部分明未。
運(yùn)行時(shí)常量池
放常量,屬于方法區(qū)的一部分壹蔓。
本地方法棧
為運(yùn)行本地方法準(zhǔn)備的空間趟妥,由于很多本地方法使用C語言數(shù)顯,所以也叫C棧佣蓉。JIT技術(shù)就是將一些Java方法重新編譯成本地代碼披摄,然后哦這些編譯后的本地代碼就是用這個(gè)棧跟蹤方法執(zhí)行狀態(tài)。
內(nèi)存分配策略
- 靜態(tài)內(nèi)存分配
- 棧內(nèi)存分配
- 堆內(nèi)存分配
靜態(tài)內(nèi)存分配指在程序編譯時(shí)就能確定每個(gè)數(shù)據(jù)在運(yùn)行時(shí)需求勇凭,然后就可以分配固定的內(nèi)存空間疚膊。不允許在程序中出現(xiàn)可變數(shù)據(jù)結(jié)構(gòu),或者嵌套或遞歸虾标,因?yàn)殡y以計(jì)算存儲(chǔ)空間需求寓盗。靜態(tài)內(nèi)存分配效率最快。
棧內(nèi)存分配也稱動(dòng)態(tài)分配璧函,運(yùn)行時(shí)才知道內(nèi)存大小傀蚌,但規(guī)定進(jìn)入一個(gè)程序模塊的時(shí)候就要知道數(shù)據(jù)大小并分配內(nèi)存。和結(jié)構(gòu)棧一樣柳譬,棧式內(nèi)存分配按照先進(jìn)后出的形式分配
堆分配喳张,是真正運(yùn)行到相應(yīng)代碼才知道內(nèi)存空間需求,這時(shí)候要用堆分配美澳。
JVM內(nèi)存回收策略
如何識(shí)別垃圾销部,只要某個(gè)對(duì)象不再被其他活動(dòng)對(duì)象引用摸航,那么這個(gè)對(duì)象就可以回收。這里活動(dòng)對(duì)象指能被一個(gè)根對(duì)象集合到達(dá)的對(duì)象舅桩。
根對(duì)象集合如下:
- 在方法中局部變量區(qū)對(duì)象的引用
- Java操作棧的對(duì)象的引用
- 常量池對(duì)象的引用
- 本地方法中持有的對(duì)象的引用
- 類的Class對(duì)象
垃圾收集算法有很多
但是大同小異酱虎,基本是基于分代的方法。
我們會(huì)將堆分成三個(gè)子堆擂涛,Young Old Perm三個(gè)區(qū)
1.Young區(qū)就是新對(duì)象申請(qǐng)的內(nèi)存的位置读串。一般來說Young區(qū)會(huì)分成Eden區(qū)和Survivor區(qū)域,新生成的對(duì)象放在Eden區(qū)撒妈,當(dāng)Eden區(qū)滿時(shí)會(huì)觸發(fā)minor GC 回收Eden區(qū)中不活動(dòng)的對(duì)象恢暖,然后存活的對(duì)象會(huì)移動(dòng)survivor,然后survivor滿了會(huì)移動(dòng)到old區(qū)狰右。
2.一般來說杰捂,old區(qū)是來自young區(qū)的對(duì)象,但是也會(huì)出現(xiàn)新對(duì)象直接生成在old區(qū)的情況棋蚌。當(dāng)old區(qū)滿了會(huì)觸發(fā)Full GC機(jī)制嫁佳。
3.Perm區(qū)主要是存放類的class對(duì)象。
4.Full GC會(huì)回收一切堆中不活動(dòng)的對(duì)象