發表文章

目前顯示的是 11月, 2019的文章

Java 運行時的jvm劃分

圖片
程序計數器 記錄當前線程所執行的字節碼行號,用於獲取下一條執行的字節碼。 當多線程運行時,每個線程切換後需要知道上一次所運行的狀態、位置。 由此也可以看出程序計數器是每個線程 私有 的。 虛擬機棧 虛擬機棧由一個一個的棧幀組成,棧幀是在每一個方法調用時產生的。 每一個棧幀由 局部变量区 、 操作数栈 等組成。 每創建一個棧幀壓棧,當一個方法執行完畢之後則出棧。 如果出現方法遞歸調用出現死循環的話就會造成棧幀過多,最終會拋出 StackOverflowError 。 若線程執行過程中棧幀大小超出虛擬機棧限制,則會拋出 StackOverflowError 。 若虛擬機棧允許動態擴展,但在嘗試擴展時內存不足,或者在為一個新線程初始化新的虛擬機棧時申請不到足夠的內存,則會拋出  OutOfMemoryError 。 這塊內存區域也是線程私有的。 Java 堆 Java  堆是整個虛擬機所管理的最大內存區域,所有的對象創建都是在這個區域進行內存分配。 可利用參數 -Xms -Xmx 進行堆內存控制。 這塊區域也是垃圾回收器重點管理的區域,由於大多數垃圾回收器都採用 分代回收算法 ,所有堆內存也分為 新生代 、 老年代 ,可以方便垃圾的準確回收。 這塊內存屬於線程共享區域。 方法區(JDK1.7) 方法區主要用於存放已經被虛擬機加載的類信息,如 常量,静态变量 。 這塊區域也被稱為 永久代 。 可利用參數 -XX:PermSize -XX:MaxPermSize 控制初始化方法區和最大方法區大小。 元數據區(JDK1.8) 在 JDK1.8 中已經移除了方法區(永久代),並使用了一個元數據區域進行代替( Metaspace )。 默認情況下元數據區域會根據使用情況動態調整,避免了在1.7中由於加載類過多從而出現 java.lang.OutOfMemoryError: PermGen 。 但也不能無限擴展,因此可以使用 -XX:MaxMetaspaceSize 來控制最大內存。 運行時常量池 運行時常量池是方法區的一部分,其中存放了一些符號引用。 當 new 一個對象時,會檢查這個區域是否有這個符號的引用。 直接內存 直接內存又稱為 Direct Mem...

ConcurrentHashMap和Hashtable的區別

圖片
ConcurrentHashMap和Hashtable的區別主要體現在實現線程安全的方式上不同。 哈希數據和JDK1.8之前的HashMap。的大部分數據結構類似都是採用副本+鍊錶的形式,排列為HashMap的主體,鍊錶則是主要為了解決哈希衝突而存在的; 實現線程安全的方式(重要):①在JDK1.7的時候,ConcurrentHashMap(分段鎖)對整個桶分段進行了分割分段(Segment),每個把鎖只鎖容器其中一部分數據,多線程訪問到了JDK1.8的時候已經替換棄了Segment的概念,直接用節點上的數據鏈+鍊錶+紅黑樹的數據結構來實現。容器裡不同數據段的數據,就不會存在鎖競爭,提高並發訪問率。 (JDK1.6之後對ynchronized鎖做了很多優化)整個看起來就像是優化過且線程安全的HashMap,雖然在JDK1.8中還能看到Segment的數據。結構,但是已經簡化了屬性,只是為了兼容舊版本;②Hashtable(同一把鎖):使用同步來保證線程安全,效率非常低下。當一個線程訪問同步方法時,其他線程也訪問同步方法,可能會進入雙向或偏置狀態,如使用put添加元素,另一個線程不能使用put添加元素,也不能使用get,競爭會越來越激烈效率越低。 两者的对比图: 图片来源: http://www.cnblogs.com/chengxiao/p/6842045.html HashTable: JDK1.7的ConcurrentHashMap: JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点):