JVM、GC與HashMap


阿里巴巴突然來了個面試邀請電話,問了些java底層的東西,不知所措,所以專門花了些時間做了下學習,順便記錄下,好記性不如爛筆頭。

一、對JAVA的垃圾回收機制(GC)的理解

  不同於C/C++需要手工釋放對象所占的內存,JAVA全部委托給了GC進行處理,能更有效的防止內存泄漏的情況。一個程序對應着一個JVM,每個JVM會單獨有一個堆,java中創建的對象與數組是存放在堆中的,堆中的內存由GC進行管理(棧中存儲引用變量、局部變量一級基本數據類型,超出作用域就會立即釋放內存)。

  當一個對象沒有再被引用時就會被GC標記為可回收狀態,然后在一個不確定的時間對其進行回收(一般是在應用程序空閑或者java堆內存不足是被調用),當然在對一個對象進行回收時,首先會執行其finalize()方法,在finalize()方法中你可再次將該對象變為活躍狀態,阻止其回收。  

  一個對象還有沒有再被引用一般有兩種判斷方式:

  1、(JDK1.2之前)每個對象都有一個引用計數器,每多一個引用,計數器+1,少一個則-1,當計數器為0時,則表示該對象沒有再被引用了。

  2、根搜索算法。這里要盜一張圖了:

    

  從GC ROOT開始,尋找對應的引用節點,找到這個節點以后,繼續尋找這個節點的引用節點,當所有的引用節點尋找完畢之后,剩余的節點則被認為是沒有被引用到的節點,即無用的節點。  

  java中可作為GC Root的對象有:

    1.虛擬機棧中引用的對象(本地變量表)

    2.方法區中靜態屬性引用的對象

    3. 方法區中常量引用的對象

    4.本地方法棧中引用的對象(Native對象)

  GC在回收這些空閑對象時會采用標記-復制算法處理:

    

    標記從根節點出發的所有在用對象,然后按順序復制到一塊新內存上,然后再回收舊內存。這樣就不會造成造成內存碎片,但是需要一塊額外的內存交換空間來進行復制。

 

二、對HashMap的理解

  HashMap結構其實是一個數組+鏈表的結構。HashMap有一個叫做Entry的內部類,它用來存儲key-value對。如下圖:

      

static class Entry implements Map.Entry
{
        final K key;
        V value;
        Entry next;
        final int hash;
        ...//More code goes here
}   `

 

    

    創建一個HashMap時會首先創建一個叫做table的Entry數組:

    

    table的默認大小是16。當往map里面存數據時,也就是執行put方法時,首先會調用key的HashCode()方法,然后進行hash計算,計算出其對應在table的index,如果table的index位置上已經有Entry了,首先會判斷該Entry的key與要put的key是否相同,如果相同則會替換,如果不同則會根據鏈表繼續判斷,即與當前位置的Entry的next指向的下一個Entry的key進行比較,直到遇到相同的key進行替換或者在鏈表末尾創建一個Entry。

 1 /**
 2   * Associates the specified value with the specified key in this map. If the
 3   * map previously contained a mapping for the key, the old value is
 4   * replaced.
 5   *
 6   * @param key
 7   *            key with which the specified value is to be associated
 8   * @param value
 9   *            value to be associated with the specified key
10   * @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
11   *         if there was no mapping for <tt>key</tt>. (A <tt>null</tt> return
12   *         can also indicate that the map previously associated
13   *         <tt>null</tt> with <tt>key</tt>.)
14   */
15  public V put(K key, V value) {
16   if (key == null)
17    return putForNullKey(value);
18   int hash = hash(key.hashCode());
19   int i = indexFor(hash, table.length);
20   for (Entry<k , V> e = table[i]; e != null; e = e.next) {
21    Object k;
22    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
23     V oldValue = e.value;
24     e.value = value;
25     e.recordAccess(this);
26     return oldValue;
27    }
28   }
29  
30   modCount++;
31   addEntry(hash, key, value, i);
32   return null;
33  }

  從map中取值時也就是執行get()方法也是類似的道理,先計算出key對應table的index,然后在鏈表上一層一層往下找:

 1 /**
 2   * Returns the value to which the specified key is mapped, or {@code null}
 3   * if this map contains no mapping for the key.
 4   *
 5   * <p>
 6   * More formally, if this map contains a mapping from a key {@code k} to a
 7   * value {@code v} such that {@code (key==null ? k==null :
 8   * key.equals(k))}, then this method returns {@code v}; otherwise it returns
 9   * {@code null}. (There can be at most one such mapping.)
10   *
11   * </p><p>
12   * A return value of {@code null} does not <i>necessarily</i> indicate that
13   * the map contains no mapping for the key; it's also possible that the map
14   * explicitly maps the key to {@code null}. The {@link #containsKey
15   * containsKey} operation may be used to distinguish these two cases.
16   *
17   * @see #put(Object, Object)
18   */
19  public V get(Object key) {
20   if (key == null)
21    return getForNullKey();
22   int hash = hash(key.hashCode());
23   for (Entry<k , V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) {
24    Object k;
25    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
26     return e.value;
27   }
28   return null;
29  }

    備注:

    1、無論你何時實現 equals 方法,你必須同時實現 hashCode 方法。在一個運行的進程中,相等的對象必須要有相同的哈希碼。不相等的對象哈希碼有可能相同,有同一個哈希值的對象不一定相等。

    2、HashMap有兩個參數影響其性能:初始容量加載因子。默認初始容量是16,加載因子是0.75。容量是哈希表中桶(Entry數組)的數量,初始容量只是哈希表在創建時的容量。加載因子是哈希表在其容量自動增加之前可以達到多滿的一種尺度。當哈希表中的條目數超出了加載因子與當前容量的乘積時,通過調用 rehash 方法將容量翻倍。

 

希望大家能一起交流,一起學習!

 

參考文章鏈接:

http://www.importnew.com/16517.html

http://www.importnew.com/10620.html

http://jbutton.iteye.com/blog/1569746

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM