程序总是在两三天就报一次内存泄漏的异常,不知道是什么原因引起的,因为项目中有一个地方冲到队列,在队列中创建了很多的线程不知道是不是这个引起了。。。
public class GlobalVariables {
public static ExecutorService pool = Executors.newFixedThreadPool(1000);
public static BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(1000);
public static Map<Integer, Integer> map = new HashMap<Integer, Integer>();
}
public class AddQueues implements Runnable{
private Object obj;
public AddQueues(Object obj) {
this.obj = obj;
}
@Override
public void run() {
try {
System.out.println("-------------"+obj);
GlobalVariables.queue.put(obj);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public Map<String, Object> updateQueuePool(Map<String, Object> map) throws Exception {
EntranceVisitCountDTO dto = new EntranceVisitCountDTO();
dto.setAdminUserId(Integer.parseInt(map.get("adminUserId").toString()));
GlobalVariables.pool.submit(new AddQueues(dto));
Map<String,Object> param = new HashMap<String,Object>();
param.put("result", "yes");
return param;
}
/**
* 定时将队列里的数据放到map中
*/
@Scheduled(cron = "0/3 * * * * ?")
public synchronized void updateVisitCountOfMap(){
try{
if(!GlobalVariables.queue.isEmpty()){
for(int i = 0; i < 100; i++){
Object obj = GlobalVariables.queue.take();
if(obj instanceof EntranceVisitCountDTO){
EntranceVisitCountDTO dto = (EntranceVisitCountDTO)obj;
Integer visitCount = GlobalVariables.map.get(dto.getAdminUserId());
if(visitCount != null && GlobalVariables.map.size() <= 1000){
GlobalVariables.map.put(dto.getAdminUserId(), visitCount +1);
}else if(GlobalVariables.map.size() > 1000){
visitDayCountService.updateEntranceShowCount();
}else{
GlobalVariables.map.put(dto.getAdminUserId(), 1);
}
}
if(GlobalVariables.queue.isEmpty()){
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 定时将map中的缓存数据同步入口
*/
@Scheduled(cron = "0 0/10 * * * ?")
public synchronized void updateEntranceShowCount(){
try{
visitDayCountService.updateEntranceShowCount();
} catch (Exception e) {
e.printStackTrace();
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public synchronized void updateEntranceShowCount() throws Exception {
if(!GlobalVariables.map.isEmpty()){
for(Map.Entry<Integer, Integer> entry : GlobalVariables.map.entrySet()){
String day = TimeUtils.getSpecifyDate(0, "yyyy-MM-dd");
VisitDayCount visitDayCount = (VisitDayCount)visitDayCountDao.getEntranceCountByEntranceInfoIdWithCreateDate(entry.getKey(), day, "VisitDayCount");
if(null == visitDayCount){
visitDayCount = new VisitDayCount();
visitDayCount.setNum(1);
visitDayCount.setAdminUserId(entry.getKey());
visitDayCount.setVisitTime(day);
visitDayCountDao.save(visitDayCount);
}else{
visitDayCountDao.updateEntranceVistCount(entry.getKey(), entry.getValue());
}
GlobalVariables.map.remove(entry.getKey());
}
}
}
このコードのエントリ ポイントは、updateQueuePool メソッドである必要があります。このメソッドは DTO を生成し、その DTO をキューに追加します。このキューのコンシューマは updateVisitCountOfMap です。 updateQueuePooll メソッドの呼び出し頻度が消費頻度よりも高い場合、遅かれ早かれ OOM が発生します
GlobalVariables.map にも同様の問題があり、3 秒ごとに最大 100 個のオブジェクトが配置されますが、10 分ごとに消費されます。
GlobalVariables のいくつかのフィールドは public です。これは、任意のコードを直接使用できることを意味します。これも問題を引き起こす可能性がある要因です。
メモリ リークがある場合、System.gc を呼び出しても解決しません。
このコードには多くの問題がありますが、完全なコードではないため、どこでメモリ リークが発生するかを判断することはできません。しばらくコードを実行してから、jmap dump を使用して確認することをお勧めします。 jvm をダウンロードし、仮想 vm を使用してファイルをダンプし、それがキューによって参照されているオブジェクトであるか、またはリサイクルされていないマップ内のオブジェクトであるかを確認します。
'新しいネイティブ スレッドを作成できません'
この種の OOM はまれです。コード内の定数 new Thread() が原因であると考えられます。
スレッドプールに変更します。
設定したスレッド プールのサイズは 1000 です。それほど多くのスレッドを構築する必要はありません。最初にホストのコアとスレッドの数を確認してください。さらに、jvm 内の xxs 割り当てのサイズは、jvm 内で開くことができるスレッドの数に影響します。 xmxのサイズを確認しています。