2013年6月4日 星期二

衡量 ReentrantReadWriteLock 的記憶體使用量

考慮使用 ReentrantReadWriteLock 來處理 Concurrent 的問題
但要這樣做的話,ReentrantReadWriteLock 有可能要全部暫存在記憶體裡面~
因此要簡單地先衡量使用 ReentrantReadWriteLock 有可能要處理多少程度的記憶體問題。

測試的程式碼很簡單,就是放一個 static 的 ConcurrentHashMap
使用 UUID 來作為 Map 的 Key,一個 UUID 對應一個 ReentrantReadWriteLock。
程式碼如下:
import java.util.Calendar;
import java.util.Calendar;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/lock")
public class LockTesting {
  private static ConcurrentHashMap<UUID, ReentrantReadWriteLock> LOCK_POOL = null;
  
  static {
    LOCK_POOL = new ConcurrentHashMap<UUID, ReentrantReadWriteLock>();
  }
  
  @GET
  @Path("/init")
  @Produces(MediaType.APPLICATION_JSON)
  public Response createLocks () {
    LOCK_POOL.clear();
    System.out.println("Start generating locks.");
    long start = Calendar.getInstance().getTimeInMillis();
    
    for(int i=0 ; i<1000000 ; i++) {
      UUID id = UUID.randomUUID();
      while(LOCK_POOL.containsKey(id))
        id = UUID.randomUUID();
      
      LOCK_POOL.put(id, new ReentrantReadWriteLock());
    }
    
    System.out.println("Generate " + LOCK_POOL.size() + " locks with " + (Calendar.getInstance().getTimeInMillis()-start) + "ms.");
    return Response.ok().build();
  }
}

也就是呼叫了 createLocks() 之後,會先把現有的資料全部清掉,然後計時並開始產生隨機的 UUID 以及對應的 ReentrantReadWriteLock
執行期間都使用 jProfiler 7 來監控執行前到執行後的記憶體變化。

開始執行之前,記憶體的狀況如圖。可以看出未執行前,Heap 的記憶體使用量是用了 18.15MB。


VM Telemetry Views


Memory Views

呼叫了 createLocks() 之後,程式碼回應如下:
Start generating locks.
Generate 1000000 locks with 15746ms.

而記憶體的使用狀況則如圖。

VM Telemetry Views


Memory Views

亦即,連續產生 100 萬個 ReentrantReadWriteLock 的所需時間其實也不算長,至少都在 16 秒以內
不過 100 萬個 ReentrantReadWriteLock 放在記憶體裡面,大概要吃 109,382KB(即約 109MB)的記憶體
換言之,一個 ReentrantReadWriteLock 可能大概是 0.109KB?說不上很省,但應該也不算太吃記憶體吧~。

而對於 UUID 來說,100 萬個 UUID 在記憶體要吃 62,500KB(即約 62MB)。

PS. 如果把 UUID 轉成 String 存放的話,記憶體使用量會暴增 XD。

沒有留言: