最近重構項目遇到一個問題。一個本地緩存的Map凌晨定時清除數據,但好幾天了都沒清除。內存累加,執行500W的數據會增長將近2.86G的內存,雖然暫時服務器還夠用,不過感覺總有一天會掛掉。
啓動時內存佔用:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
81159 root 20 0 28.951g 1.320g 14724 S 0.0 1.1 0:12.76 java
執行500W數據後的內存佔用:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
81159 root 20 0 33.399g 4.186g 14956 S 0.0 3.3 14:14.34 java
Map定義如下:
public static Map<Integer, Map<Long, List<Long>>> USER_REPEAT = new ConcurrentHashMap<Integer, Map<Long, List<Long>>>();
百度了一下解決方法,說靜態變量無法被GC,而且如果有地方引用也不會回收。不過new的對象可以被回收。
第一種,調用clear()方法後設置map=null;
USER_REPEAT.clear();
USER_REPEAT=null;
第二種,循環刪除;
for (Map.Entry<Integer, Map<Long, List<Long>>> entry : USER_REPEAT.entrySet()) {
USER_REPEAT.remove(entry.getKey());
}
測試上面兩張方法後GC,內存無明顯變化。
想了一下是不是可能兩層嵌套的原因。寫了個循環刪除。果然刪除後內存有明顯的變化。
Map<Long, List<Long>> subMap = null;
for (Integer key : USER_REPEAT.keySet()) {
subMap = USER_REPEAT.get(key);
for (Long subKey : subMap.keySet()) {
subMap.remove(subKey);
}
USER_REPEAT.remove(key);
}
測試95W簡單數據內存變化
監控堆從163M降到10M
分析了下原因應該是直接刪除key但是沒有刪除子Map中對List的引用,導致內存不釋放。