1棧幀(stack)
2堆(heap)
3方法區(Method area)
4本地方法棧(Native method stack)
5寄存器(ProgramCounter register)java
1棧幀(stack)
每一個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象),對象都存放在堆區中
每一個棧中的數據(原始類型和對象引用)都是私有的,其餘棧不能訪問。
棧分爲3個部分:基本類型變量區、執行環境上下文、操做指令區(存放操做指令)。
區域小,只有1M,存取速度快,速度僅次於寄存器
stack(棧)會建立類對象的引用(內存地址)。算法
FILO先進後出,暫存數據的地方。每一個線程都包含一個棧區!棧存放在一級緩存中,存取速度較快,「棧是限定僅在表頭進行插入和刪除操做的線性表」。數組
2堆(heap)
存放對象或數組
線程共享
GC主要管理緩存
FIFO隊列優先,先進先出。jvm只有一個堆區被全部線程所共享!堆存放在二級緩存中,調用對象的速度相對慢一些,生命週期由虛擬機的垃圾回收機制定框架
3方法區(Method area)jvm
類的方法代碼,常量,靜態變量,方法名,訪問權限,返回值等等都類的方法代碼,常量,靜態變量,方法名,訪問權限,返回值等都在方法區
保存裝載的類信息
類型的常量池
字段,方法信息
方法字節碼
一般和永久區(Perm)關聯在一塊兒線程
4本地方法棧(Native method stack)
線程私有,支撐本地方法,對外系統交互等
java調用非java代碼的接口。一個Native Method是這樣一個java的方法:該方法的實現由非java語言實現,代理
5寄存器(ProgramCounter register)
速度最快,個數有限
每一個線程擁有一個PC寄存器
在線程建立時建立
指向下一條指令的地址
執行本地方法時,PC的值爲undefinedcode
棧和堆的區別對象
Java中的參數傳遞( 傳值呢?仍是傳引用? ):
新生代分爲三個區域,一個Eden區和兩個Survivor區,它們之間的比例爲(8:1:1),這個比例也是能夠修改的。一般狀況下,對象主要分配在新生代的Eden區上,少數狀況下也可能會直接分配在老年代中。Java虛擬機每次使用新生代中的Eden和其中一塊Survivor(From),在通過一次Minor GC後,將Eden和Survivor中還存活的對象一次性地複製到另外一塊Survivor空間上(這裏使用的複製算法進行GC),最後清理掉Eden和剛纔用過的Survivor(From)空間。將此時在Survivor空間存活下來的對象的年齡設置爲1,之後這些對象每在Survivor區熬過一次GC,它們的年齡就加1,當對象年齡達到某個年齡(默認值爲15)時,就會把它們移到老年代中。
在新生代中進行GC時,有可能遇到另一塊Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象,這些對象將直接經過分配擔保機制進入老年代;
1.Eden區
Eden區位於Java堆的年輕代,是新對象分配內存的地方,因爲堆是全部線程共享的,所以在堆上分配內存須要加鎖。而Sun JDK爲提高效率,會爲每一個新建的線程在Eden上分配一塊獨立的空間由該線程獨享,這塊空間稱爲TLAB(Thread Local Allocation Buffer)。在TLAB上分配內存不須要加鎖,所以JVM在給線程中的對象分配內存時會盡可能在TLAB上分配。若是對象過大或TLAB用完,則仍然在堆上進行分配。若是Eden區內存也用完了,則會進行一次Minor GC(young GC)。
2.Survival from to
Survival區與Eden區相同都在Java堆的年輕代。Survival區有兩塊,一塊稱爲from區,另外一塊爲to區,這兩個區是相對的,在發生一次Minor GC後,from區就會和to區互換。在發生Minor GC時,Eden區和Survivalfrom區會把一些仍然存活的對象複製進Survival to區,並清除內存。Survival to區會把一些存活得足夠舊的對象移至年老代。
3.年老代
年老代裏存放的都是存活時間較久的,大小較大的對象,所以年老代使用標記整理算法。當年老代容量滿的時候,會觸發一次Major GC(full GC),回收年老代和年輕代中再也不被使用的對象資源。
總結:
一、Minor GC是發生在新生代中的垃圾收集,採用的複製算法;
二、新生代中每次使用的空間不超過90%,主要用來存放新生的對象;
三、Minor GC每次收集後Eden區和一塊Survivor區都被清空;
四、老年代中使用Full GC,採用的標記-清除算法
注意:
堆=新生代+老年代,不包括永久代(方法區)。
不少人認爲方法區(或者HotSpot虛擬機中的永久代)是沒有垃圾收集的,Java虛擬機規範中確實說過能夠不要求虛擬機在方法區實現垃圾收集,並且在方法區進行垃圾收集的「性價比」通常比較低:在堆中,尤爲是在新生代中,常規應用進行一次垃圾收集通常能夠回收70%~95%的空間,而永久代的垃圾收集效率遠低於此。
永久代的垃圾收集主要回收兩部份內容:廢棄常量和無用的類。回收廢棄常量與回收Java堆中的對象很是相似。以常量池中字面量的回收爲例,假如一個字符串「abc」已經進入了常量池中,可是當前系統沒有任何一個String對象是叫作「abc」的,換句話說是沒有任何String對象引用常量池中的「abc」常量,也沒有其餘地方引用了這個字面量,若是在這時候發生內存回收,並且必要的話,這個「abc」常量就會被系統「請」出常量池。常量池中的其餘類(接口)、方法、字段的符號引用也與此相似。
斷定一個常量是不是「廢棄常量」比較簡單,而要斷定一個類是不是「無用的類」的條件則相對苛刻許多。類須要同時知足下面3個條件才能算是「無用的類」:
該類全部的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
加載該類的ClassLoader已經被回收。
該類對應的java.lang.Class 對象沒有在任何地方被引用,沒法在任何地方經過反射訪問該類的方法。
虛擬機能夠對知足上述3個條件的無用類進行回收,這裏說的僅僅是「能夠」,而不是和對象同樣,不使用了就必然會回收。是否對類進行回收,HotSpot虛擬機提供了-Xnoclassgc參數進行控制,還可使用-verbose:class及-XX:+TraceClassLoading、 -XX:+TraceClassUnLoading查看類的加載和卸載信息。
在大量使用反射、動態代理、CGLib等bytecode框架的場景,以及動態生成JSP和OSGi這類頻繁自定義ClassLoader的場景都須要虛擬機具有類卸載的功能,以保證永久代不會溢出
在Java中,堆被劃分紅兩個不一樣的區域:年輕代、老年代。年輕代(Young)又被劃分爲三個區域:Eden、S0、S1。這樣劃分的目的是爲了使JVM可以更好的管理堆內存中的對象,包括內存的分派以及回收。
堆是GC收集垃圾的主要區域。GC分爲兩種:Minor GC、Full GC。
1.年輕代
年輕代用來存放新近建立的對象,尺寸隨堆大小的增長和減小而相應的變化,默認值是保持爲堆的1/15.能夠經過-Xmn參數設置年輕代爲固定大小,也能夠經過 -XX:NewRatio 來設置年輕代與年老代的大小比例,年輕代的特色是對象更新速度快,在短期內產生大量的「死亡對象」。
年輕代的特色是產生大量的死亡對象,而且要是產生連續可用的空間, 因此使用複製清除算法和並行收集器進行垃圾回收.對年輕代的垃圾回收稱做初級回收 (minor gc)。
初級回收將年輕代分爲三個區域,一個新生代,2個大小相同的復活代,應用程序只能使用一個新生代和復活代,當發生初級回收時,gc掛起程序,而後將新生代和復活代中的存貨對象複製到另一個復活代中,而後一次性消除新生代和復活代,將原來的非復活代標記成活動復活代。將在指定次數回收後仍然存在的對象移動到老年代中,初級回收後,獲得一個空的可用的新生代。
新生代幾乎是全部Java對象出生的地方,即Java對象申請的內存以及存放都是在這個地方。Java中的大部分對象一般不需長久存貨,具備朝生夕滅的性質。當一個對象唄斷定爲「死亡」的時候,GC就有責任來回收掉這部分對象的內存空間。新生代是GC收集的頻繁區域。當對象在Eden出生後,在通過一次Minor GC後,若是對象還存活,而且可以被另一塊Survivor區域所容納,則使用複製算法將這些仍然還活着的對象複製到另一塊Survivor區域中,而後清理所使用過的Eden和Survivor區,而且將這些對象的年齡設置爲1,之後對象在Survivor區每通過一次Minor GC,就將對象的年齡加1,當對象的年齡達到某個值時(默認是15歲)這些對象就會成爲老年代。
2.老年代
Full GC 是發生在老年代的垃圾收集動做,所採用的是標記-清除算法。
現實的生活中,老年代的人一般會比新生代的人 「早死」。堆內存中的老年代(Old)不一樣於這個,老年代裏面的對象幾乎個個都是在 Survivor 區域中熬過來的,它們是不會那麼容易就 「死掉」 了的。所以,Full GC 發生的次數不會有 Minor GC 那麼頻繁,而且作一次 Full GC 要比進行一次 Minor GC 的時間更長。 另外,標記-清除算法收集垃圾的時候會產生許多的內存碎片 ( 即不連續的內存空間 ),此後須要爲較大的對象分配內存空間時,若沒法找到足夠的連續的內存空間,就會提早觸發一次 GC 的收集動做。