可以說,學姐給我的這份文檔真的把我的知識查漏補缺,面試問到了好多,值得收藏。
并發編程
一.Executor
為什么使用線程池:手動創建線程耗費性能,不利于管理。
首先創建線程池有兩種方式:使用Executors工廠來創建ThreadPoolExecutor這類自定義線程池。
1. 使用Executors工廠來創建
Executors是一個類,用來創建線程池,常用的有四種線程池
1.newFixedThreadPool 創建一個可重復固定的線程數的線程池
2.newCachedThreadPool 創建一個可緩存的線程池,調用execute將重復用以前構造的線程(如果當前線程可用)。如果沒有可用線程則創建新的線程并加入到池中。終止并從緩存中移除那些已有60s未被使用的線程。
3.newSingleThreadExecutor創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行
4. newScheduledThreadPool 創建一個支持定時及周期性的任務執行的線程池,多數情況下可用來替代Timer類。
使用示例:
?
?
?
2. 使用ThreadPoolExecutor這個類自定義創建線程池
?
?
二.ThreadLocal
?
三.中斷線程
1.線程執行完畢會自動結束
2.在線程處于阻塞,期限等待火無期限等待時,調用線程的interrupt()會拋出interruptedException異常從而提前終止線程
3.若沒有處于阻塞狀態,調用interrupte()將線程標記為中斷,此時在調用interrupted()判斷線程是否處于中斷狀態,來提前終止線程。
4.線程池調用shutdown()等待所有線程執行完畢之后關閉
?
?
三.Volatile關鍵字的理解
兩層語義:1.保證不同線程對該變量的內存可見線
????????? 2.禁止進行指令重排序
?
內存語義:
讀這個變量的時候,JMM會把本地內存中的變量設置為無效,從主內存中取;
寫這個變量的時候,JMM會把本地內存變量刷新到主內存當中
實現:添加Volatile關鍵字會在匯編代碼中多處一個kock前指令,也就是內存屏障
?
四.Synchronized關鍵字
(1)synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
??? 1. 修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
??? 2. 修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;
??? 3. 修飾一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;
4. 修飾一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象。
?
(2)Synchronized的作用主要有三個:(1)確保線程互斥的訪問同步代碼(2)保證共享變量的修改能夠及時可見(3)有效解決重排序問題。
(3)Synchronized 原理
??? 在編譯的字節碼中加入了兩條指令來進行代碼的同步。
??? monitorenter :
??? 每個對象有一個監視器鎖(monitor)。當monitor被占用時就會處于鎖定狀態,線程執行monitorenter指令時嘗試獲取monitor的所有權,過程如下:
??? 1.如果monitor的進入數為0,則該線程進入monitor,然后將進入數設置為1,該線程即為monitor的所有者。
??? 2.如果線程已經占有該monitor,只是重新進入,則進入monitor的進入數加1.
??? 3.如果其他線程已經占用了monitor,則該線程進入阻塞狀態,直到monitor的進入數為0,再重新嘗試獲取monitor的所有權。
??? monitorexit:
??? 執行monitorexit的線程必須是objectref所對應的monitor的所有者。
??? 指令執行時,monitor的進入數減1,如果減1后進入數為0,那線程退出monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權。
??? 通過這兩段描述,我們應該能很清楚的看出Synchronized的實現原理,Synchronized的語義底層是通過一個monitor的對象來完成,其實wait/notify等方法也依賴于monitor對象,這就是為什么只有在同步的塊或者方法中才能調用wait/notify等方法,否則會拋出java.lang.IllegalMonitorStateException的異常的原因。
(4)Synchronized的優化
(4)synchronized與Lock的區別
??? lock是一個類,主要有以下幾個方法:
??? lock():獲取鎖,如果鎖被暫用則一直等待
??? unlock():釋放鎖
??? tryLock(): 注意返回類型是boolean,如果獲取鎖的時候鎖被占用就返回false,否則返回true
tryLock(long time, TimeUnit unit):比起tryLock()就是給了一個時間期限,保證等待參數時間
?
??? (1)Lock的加鎖和解鎖都是由java代碼實現的,而synchronize的加鎖和解鎖的過程是由JVM管理的。
??? (2)synchronized能鎖住類、方法和代碼塊,而Lock是塊范圍內的。
??? (3)Lock能提高多個線程讀操作的效率;
(4)Lock:Lock實現和synchronized不一樣,后者是一種悲觀鎖,它膽子很小,它很怕有人和它搶吃的,所以它每次吃東西前都把自己關起來。而Lock底層其實是CAS樂觀鎖的體現,它無所謂,別人搶了它吃的,它重新去拿吃的就好啦,所以它很樂觀。如果面試問起,你就說底層主要靠volatile和CAS操作實現的。
五.CAS機制
Compare And Swap
CAS操作是一個原子操作,由一條CPU指令完成,使用了3個基本操作數,內存地址V,舊的預期值A ,要修改的新值B
需要更新一個變量的時候,只有當內存地址V中的值和預期值A相等的時候才會修改為新值B ,如果失敗則自旋,重新嘗試
問題:
1.ABA 解決辦法,加一個版本號,只有當版本號和預期值都符合的時候才修改
2.不能保證代碼塊的原子性,CAS機制知識保證一個變量的原子操作
五.JMM的理解
JMM的核心是找到一個平衡點,在保證內存可見性的前提下,盡量的放松對編譯器和處理器重排序的限制。
?
可能會產生緩存一致性的問題:
1.總線鎖定
2.緩存一致性協議
?
三大特性:原子性,可見性,有序性
?
?
?
六.JVM的鎖優化
1.自旋鎖和自適應自旋鎖
線程掛起和恢復都需要很大的性能開銷,很多共享數據的鎖定狀態只持續很短的時間,為這段時間掛起恢復不值得,所以可以讓現場進入一個自旋狀態,但仍占用cpu的時間,默認是10次,超過10次則采用傳統的方式掛起線程。自適應自旋鎖會根據上次在這個鎖上自旋的時間調整自選次數
?
2.鎖消除
檢測到對局部變量加鎖,會自動將鎖消除,如在一個方法里面有sb = s1 + s2 + s3以前會轉化為StringBuffer(線程安全,有加鎖)的append操作,優化之后會轉換成StringBuilder的sppend操作
?
3.鎖粗化
對一個對象反復加鎖解鎖,如上述的append方法,編譯器會優化,只在最外層加一個鎖
?
4.輕量級鎖
對象有一個對象頭,對象頭分兩部分區域,一部分存儲子樹的hashcode,GC分代年齡,鎖標志位等,官方成為mark word,另一部分用于存儲指向方法區對象類型的指針;
輕量級鎖的執行過程是代碼進入同步塊的時候,如果當前對象沒有被鎖定(鎖標志為是01)則先在線程的棧幀中建立一個鎖記錄空間(lock record)將對象的mark word拷貝過來,然后利用cas操作嘗試將對象的markword更新為指向lock record,如果成功則當前線程擁有該對象鎖,并且將鎖標志位從01改為00,如果更新失敗則會檢查當前對象markword是否指向當前線程的棧幀,如果是則直接進入同步塊執行否則說明當前的對象鎖已經被其他線程占有。如果有兩條以上的線程競爭這個鎖,那就會膨脹成重量級鎖,鎖標志為變成10;
?
5.偏向鎖
鎖對象第一次被線程獲取的時候,會將當前的鎖標志設置為偏向鎖01狀態,并使用cas操作將當前線程的id記錄在markword當中,如果成功那么在以后的操作當中不需進行任何操作就可以進入同步代碼塊,當有另外一個線程獲取當前鎖的時候,偏向模式就宣告結束,撤銷偏向鎖之后恢復到未鎖定或者輕量級鎖狀態
?
JAVA基礎
String
1.string s1 = “aaa” 與 String s1 = new String(aaa);
前者會在Stringpool中創建一個對象,如果Stringpool中已經有了,則直接引用
后者會在Stringpool和堆中分別創建一個對象,如果StringPool中已經有了則只創建一個對象
?
2.調用s1.integer()方法,可以將字符串放入StringPool中,如果已經存在則直接返回這個對象
?
?
繼承
1.幾種修飾符的訪問權限范圍
?
2. ==? equals? hashcode的關系
1.==是比較兩個對象的地址是否相等
2.equals默認和 == 一樣也是比較地址,也可以根據自己的需求來重寫什么叫做相等
3.hashcode 是根據對象的地址來返回一串int型數字,如果對象不一樣的話返回的值也不一樣
?
3.為什么重寫equals的同時也要重寫hashcode
首先必須滿足如果equals相同,那么hashcode也必須相同,如果hashcode不相同,那么equals必須不相同的原則,否則會導致該類無法與基于散列值的集合類(hashmap , hashset ,hashtable)結合正常運行
?
因為對于這些集合在進行重復性判斷時,是先用hashcode判斷,如果相同在用equals判斷
?
?
4.hash沖突的解決方法
1.開放地址法(線性探測法,二次探測法)
2.在散列函數法
3.鏈地址法
?
5.hashtable與hashmap的區別
1.hashmap線程不安全,hashtable線程安全
2.hashmap最多允許一個鍵為null,而hashtable不允許
3.hashtable中默認的hash數組大小為11,增加的方式是old*2+1,而hashmap默認是16,肯定是2的指數
4.計算hash的方法不一樣,hashtable是直接用hashcode,而hashmap使用了key的高16位和低16位做異或運算
?
Linkedhashmap繼承于hashmap,可以按順序讀取,底層使用的是雙向鏈表
TreeMap實現了sortmap接口,可以對元素進行排序,底層使用的紅黑樹
?
7.java BIO NIO AIO 序列化
字節操作:使用inputStream和outPutSream實現,字節是傳輸和存儲的最小單位
字符操作:inputStreamReader:將字節流解碼成字符流
OutPutStramWriter:將字符流編碼成字節流
對象操作:序列化就是將對象轉換成字節序列,方便存儲和運輸,兩個用途:
1.把對象的字節序列永久地保存到硬盤中,通常存放在一個文件里
2.在網絡上傳送對象的字節序列
在很多應用中,需要對某些對象進行序列化,讓他們離開內存空間,入住到物理磁盤方便長期保存,比如session對象,當有大量用戶并發訪問的時候可能會出現10萬個session對象,內存吃不消,此時就需要將這些session先序列化到硬盤中,等要用的時候在把對象還原到內存中。
當兩個進程在進行遠程通信的時候,彼此可以發送各種類型的數據,無論是何種類型的數據,都會以二進制的序列在網絡上傳送。發送方需要把這個java對象轉換成字節序列,才能在網絡上傳送;接收方則需要把字節序列恢復成java對象。
Io與NIO的區別:
1.NIO是非阻塞的
2.NIO是面向緩沖區的,IO是面向流的
?
AIO:異步非阻塞
?
?
?
8.static關鍵字的作用
一.修飾變量:
1.靜態變量在類加載的時候被創建并初始化,只被創建一次(類加載只進行一次),可以修改
2.靜態變量屬于整個類而不屬于某個對象。
?
二.修飾方法
1.可以通過類名來訪問,不需要創建對象來訪問,可以用來實現單例模式
2.靜態方法只能調用靜態方法和靜態變量
?
三.修飾靜態代碼塊
在類加載的時候執行,且只執行一次
?
9.單例模式
實現:
1.為什么要用判斷雙重:
因為可能有兩個線程都執行完了第一個if語句,如果沒有第二重判斷,那么當其中有個線程執行完synchronized里面的語句之后,另外一個線程跟著也會執行,這樣就達不到單例模式的效果
?
2.第一重判斷去掉也可以實現,為什么不去掉
這個設計性能問題,因為
參考:https://qinjiangbo.com/mechanism-of-double-locking-check.html
?
10.this與super關鍵字
?
?
9.java中的多態
分為兩種:
1.編譯時多態:體現在重載(方法名相同而參數不同),在編譯時期就根據傳入的參數確定好調用哪個方法;
2.運行時多態:體現在方法的重寫。在運行時期判斷引用類型的實際類型根據實際的類型調用其相應的方法;
當父類對象引用變量引用子類對象時,被引用對象的類型決定了調用誰的成員方法,引用變量類型決定可調用的方法。如果子類中沒有覆蓋該方法,那么會去父類中尋找。
?
參考鏈接:https://www.runoob.com/w3cnote/java-polymorphism.html
?
10.接口類和抽象類的異同
區別:
1.抽象類可以有非抽象方法,但接口只能有抽象方法
2.接口中的成員變量默認修飾為public static final(高度抽象的模版,所以這些都是提取出來的不變特征),方法默認修飾為public abstract。抽象類中的成員變量可以被不同的修飾符來修飾
3.類可以實現多個接口但只能繼承一個抽象類
?
相同:
1.不能被實例化
2.派生類都必須實現未實現的方法
?
11.instanceof
用來判斷一個對象是否是一個類的實例
12.各種排序算法復雜度及穩定性
1.java底層如何實現排序的
Java中Arrays.sort使用了兩種排序方法,快速排序和優化歸并排序。
快速排序主要針對基本的數據類型(int short long)排序,而歸并排序用于對象類型的排序
?
如果數據量小于60會使用插入排序,插入排序是穩定的
?
13.java中的堆和棧
棧:主要用于存儲局部變量和對象的引用變量,每個線程都有一個獨立的棧空間,所以線程之間是不共享數據的;
棧的特點是存取速度快,但所存數據的大小和生存期必須是確定的(編譯后就已經確定大小)
?
堆:堆中主要存儲實例化的對象和數組。線程共享。堆的優勢是可以動態的分配內存大小,生存期也不必事先告訴編譯器,但缺點是存取速度較慢
?
?
Linux基本面試題:
Ls:用于顯示指定工作目錄下的類容,不會列出詳細信息
Ll:會列出當前文件目錄的詳細信息,含有時間,權限,大小等
Cd:用于切換到目標目錄
Mkdir:用于簡歷當前目錄的子目錄
rm-r 刪除的文件或者目錄,需確認
rm –rf同上但無需確認
cp:復制文件 若復制目錄則必須加上-r
數據庫MySQL
一.索引
1.B樹,B+樹,以及兩者的區別
B樹是一種多路平衡查找樹,其每一個節點都存儲Key和data
B+樹是B樹的一個變種,葉子節點存儲data,非葉子節點只存儲key,B+樹的葉子節點增加了順序訪問指針,每一個葉子節點都可以訪問到他的下一個葉子節點
?
?
區別:
1.B+樹種只有葉子節點會帶有全部信息,非葉子節點只起到索引的作用,二B樹的所有節點都帶有全部信息,B+樹的每一層節點都會再次出現在下一層節點上
2.B+樹種所有葉子節點都是通過指針連在一起,B樹則沒有
?
2.索引的優點和缺點
優點:可以加大檢索速度
缺點:創建和維護索引需要耗費時間
?
3.Mysql為什么選擇B+樹
Mysql數據本質上是放在外部存儲的,B+樹是為了加快讀取速度二設計的一種數據結構
1.可以減少i/o次數,只有葉子節點才存儲數據,非葉子節點存儲索引,這樣一次讀取到內存的關鍵字增多,相對i/o次數也就減少(根據區別一)
2.能夠提供穩定高效的范圍掃描,因為所有的葉子節點都互相連接(根據區別二)
?
4.索引越多越好嗎?
索引可以提高select的效率,但是也降低了insert和updata的效率,因為插入和更新的時候可能會重建索引,索引怎么建索引要慎重考慮。
?
5.索引分類
1.B+樹索引:以b+樹作為數據結構的索引
2.hash索引:能以O(1)的時間復雜度查找,但失去了有序性,innodb有一個自適應哈希索引,當這個索引值被頻繁使用時會在b+樹上創建一個哈希索引
3.全文索引:用于查找文本的關鍵詞,中文需要由中文分詞插件
二. MySQL優化
一.MySQL的優化,主要分為索引的的優化,sql語句的優化,表的優化。同時可以使用緩存增加效率
1.索引的優化
只要列中含有null,最好不要再此列設置索引
對于經常在where語句中使用的列,最好設置一個索引
對于like語句,以%或者-開頭的不會使用索引,以%結尾會使用索引
?
二.sql語句的優化
查詢優化要盡量避免全表掃描
查詢時能不用*就不用*,盡量寫字段名
三. MySQL常問問題
1.數據庫如何應對大規模的寫入和讀取
(1)使用NoSQL,通過降低數據的安全性,減少對事物的支持,減少復雜查詢的支持來獲取性能的提升;但有些場合NoSQL無法滿足要求
(2)分庫分表:
水平切分:不修改數據庫的表結構,通過對表中的數據拆分而達到分片的目的,一般水平切分在查詢的時候可能會用到union操作(多個結果并)
可以根據hash或者日期來進行分表
?
垂直切分:修改表結構,按照訪問的差異將某些列拆分出去,一般查詢數據的時候可能會用到join操作;把常用的字段放在一個表中,不常用的放在一個表中;把字段比較大的比如text字段拆出來放在一個表中。
?
分庫:分表能夠解決數據量過大帶來的查詢效率下降問題,但是卻無法給數據庫的并發處理能力帶來質的提升;分庫可以對關鍵字取模的方式來對數據訪問進行路由;
?
?
?
(3)讀寫分離:
讀寫分離是在主服務器上修改數據,數據也會同步到從服務器上,從服務器只能提供讀取,不能寫入,實現備份的同時也實現了數據庫的性能優化
如何保證數據一致性:
(1)主節點
保證事務每次提交之后,要確保binlog都能刷新到磁盤中,只要有了binlog,innoDB就有方法恢復數據,不至于導致主從復制的數據丟失
(2)從節點
??? 開啟 relay log 自動修復機制,發生 crash 時,會自動判斷哪些 relay log 需要重新從master 上抓取回來再次應用,以此避免部分數據丟失的可能性。
?
2.數據庫事務及其隔離級別
事務的特性:ACID
?
事務在并發的時候,隔離性很難保證主要可能出現下面這些問題:
臟讀:一個事務讀了另外一個事務未提交的數據,如果另一個事務回滾則會發生臟讀
不可重復讀:一個事務前后讀取同一行數據,如果在這個過程中有其他事務修改了此數據則會發生不可重復讀
幻讀:一個事務前后讀取范圍的時候
?
?
?
事務隔離級別:
MySQL實現事務是基于undo/redo日志實現的:
undo日志記錄修改前的狀態,ROLLBACK基于UNDO日志實現;
REDO日志記錄修改后的狀態,事務的持久性基于REDO日志實現
?
兩種解決臟讀、不可重復讀、幻讀的方案:
MVCC(性能較高,但讀的可能是歷史版本)
1.版本鏈:對于每一行的數據,在undo日志中,總會記錄每個版本記錄以及對應的事務id,
2.readView:
核心問題:當前版本鏈中哪個版本對當前事務可見
Readview包含的內容:{當前活躍的事務id,下一個應該分配的事務id,當前自己的事務id},根據當前讀的版本事務id和這個readview對比,如果是活躍的或者大于下一個應該分配的事務id則說明當前版本對此事務不可見,應該前讀一個版本,依次類推直到找到可見的版本
提交讀:每次讀取數據前都會生成一個readview
可重復讀:在第一次讀取時句時生成一個readview
?
?
鎖(性能不高,但讀的是最新版本):
?
?
?
MyISAM和innoDB的區別
1.innodb支持行鎖,myisam不支持行鎖
2.innodb支持事務,myisam不支持事務
3.innodb支持回滾和安全回復,myisam不支持
4.innodb的索引就是數據,myisam的索引只存儲了主鍵和行號,還需要根據行號去查找相應的記錄
5.innodb更適合寫密集的表,myisam更適合讀密集的表
計算機網絡
1.tcp和udp的區別:
Udp:無連接,盡最大可能交付,沒有擁塞控制流量控制
Tcp:面向連接,可靠交付,有擁塞控制和流量控制
?
2.輸入一條url,整個過程:
1.DNS解析,獲取ip地址(本機,本地域名服務器,根域名服務器,頂級域名服務器,權限域名服務器)
2.建立TCP連接
3.瀏覽器發出http請求
4.服務器進行響應
5.TCP連接釋放
6.瀏覽器渲染
?
3.為什么是三次握手,四次揮手
三次握手:防止之前滯留的連接請求再次到達服務端
四次揮手:因為tcp是全雙工模式,客戶端停止發送請求之后,服務端也要停止發送請求
?
4.time_wait存在的原因,時間是多少(兩倍的報文最大存活時間)
1.確保客戶端發送的最后一個報文能被收到,服務端可以正常關閉。
2.讓所有報文都在網絡中消失,時間是兩倍的最大報文存活時間。
?
5.tcp的可靠傳輸靠什么:
超時重傳:如果已經發送的報文在超過時間內沒有被確認,那么就重新發送這個報文
?
6.Tcp的滑動窗口
發送方和接收方都有一個滑動窗口
?
7.TCP流量控制
流量控制是為了控制發送方的發送速率,保證接收方來得及接收
通過滑動窗口來控制,根據報文知道對方窗口的大小,然后根據窗口大小來控制發送速率
?
?
?
8.TCP擁塞控制
如報文過多,會導致超時重傳,又會導致網絡更加阻塞
1.慢開始和擁塞避免:
慢開始:設置初始的報文數量為1;
擁塞避免:設置一個閾值,當報文數超過這個閾值的時候每次,報文每次加一,如果出現超時領閾值等于當前報文的一半,重新執行慢開始
?
快重傳:如果收到3個確認報文,則重傳丟失的那個報文
快恢復:這種情況令閾值等于當前報文的一半,并令當前發送的報文數等于閾值,因為沒有出現網絡阻塞
?
?
http各個版本的區別
http0.9 : 僅支持GET請求,僅能訪問html資源
http 1.0 :增加了post和head請求
http1.1 : 增加了長連接,一個tcp連接可以發送多個http請求,新增了put,patch,delete請求
http2.0 : 增加了雙工模式,不僅客戶端能發送多個請求,服務端也能處理多個請求
Redis
1.redis的數據淘汰策略
當redis內存數據大小達到一定的大小時,就會施行數據淘汰策略,主要有六種策略
?
2.數據庫和緩存的數據一致性
2.1 mySQL里有2000w數據,redis中只存20w的數據,如何保證redis中的數據都是熱點數據
根據數據淘汰策略,先算一下這20W的數據大概占多少內存,然后設置redis的內存,啟用從所有數據集中挑選最近最少使用的淘汰策略
?
2.2 redis緩存和mysql數據庫同步
?
?
?
3.Redis持久化
1.RDB持久化(redis默認方式)
將某個時間點的所有數據都存在硬盤中,如果發生故障將丟失最后一次創建快照的數據
觸發RDB快照的條件:在指定的時間間隔內,執行指定次數的寫操作
2.AOF持久化
所執行的每一條指令,都會記錄到appendonly.aof文件中,redis會按照策略將指令存入硬盤中。當redis重啟的時候會根據日志文件的內容將寫指令從前到后執行一次完成數據恢復的功能
?
?
Java異常體系
Error:主要是虛擬機產生,與代碼編寫者無關,例如:outOfMemoryError
?
Exception:主要有運行時異常和io異常
運行時異常:數組越界,空指針異常
Io異常:找不到文件
?
發生oom的可能區域:
除了程序計數器都有可能發生
虛擬機棧:當jvm嘗試去擴展棧空間失敗時可能會拋出oom異常
堆:堆中對象堆積起來無法釋放
方法區
?
?
四種引用類型:
主要體現在對象不可達性和對垃圾回收的影響:
強引用:只要有強引用指向一個對象,就表面對象還活著,垃圾回收期不會碰這種對象
軟引用:只有當jvm認為內存不足的時候才會去試圖回收這些對象
弱引用:不能使對象豁免垃圾回收,只是提供一種對象的訪問途徑
虛引用:不能提供他訪問對象,僅僅提供一種確保對象唄finalize之后做某些事情的機制
?
?
?
JAVA虛擬機是如果加載類的
1.加載:主要是用類加載器(啟動類加載器,擴展類加載器,應用類加載器)來查找對應類的字節流
雙親委派的好處:由于類隨著類加載器一起有一種優先級的層級關系,從而使基礎類得到統一
?
2.鏈接
驗證:確保字節流的安全性,不會對虛擬機造成危害
準備:為類的靜態字段分配內存
解析:將符號引用解析成實際引用
?
3.初始化:調用<clinit>方法,為靜態變量賦與實際的值,執行靜態代碼塊
運行時數據區域:
?
?
?
運行時內存區域:
1.程序計數器:記錄正在執行虛擬機字節碼的指令地址
2.java虛擬機棧:主要存儲局部變量表
3.本地方法棧
4.堆:存儲對象的地方,有新生代和老年代
5.方法區:存儲類信息,常量,靜態變量等信息
?
內存分配策略:
1.對象優先在eden區域分配
2.大對象直接進入老年代
3.長期存活的對象進入老年代:會有一個年齡計數器,達到指定的閾值就會進入老年代
?
FullGC觸發條件:
1.調用system.gc()
2.老年代空間不足
3.minor GC時老年代空間分配擔保失敗