最近在检查模块代码的时候看到如下一段代码:
this.suplyRecord()从DB中取得指定数量的记录,放到缓存队列中。客户程序通过getProductBlock()从队列中获得数据。由于处理的瓶颈在与数据库交互这边,所以通过引入这种机制,以降低了查库频率,从而提高程序的整体处理效率。
考虑到this.suplyRecord()在取数据时,有可能获得空的数据集(也就是表中可能也没有记录了),supply方法在数据集为空时会休眠5分钟。休眠醒来通过this.getProductBlock()
再次检测数据集,如果数据集为空,则可能再次休眠。
这样会引发什么问题呢?
如果数据库中一直有未处理的记录,或者每隔一小段时间,就有未处理的数据入库,那么事情就没有问题,递归很快返回。但是如果一整天都没有新进来的未处理数据,那么由于是递归,那么递归的堆栈会累得非常高,消耗大量内存,到最后就可能OOM了。
下面的代码可以验证这种情景:
看看,附件中,这个代码产生的堆栈。
//获得一个产品块
public Vector<Product> getProductBlock() throws Exception {
//缓存队列中已经没有数据了,则补充数据
if (cacheQueue.isEmpty()) {
//补充数据
this.supplyRecord();
//有可能引发问题的递归调用!!
return this.getProductBlock();
}
//获得缓存队列中的第一块数据
return cacheQueue.remove(0);
}
this.suplyRecord()从DB中取得指定数量的记录,放到缓存队列中。客户程序通过getProductBlock()从队列中获得数据。由于处理的瓶颈在与数据库交互这边,所以通过引入这种机制,以降低了查库频率,从而提高程序的整体处理效率。
考虑到this.suplyRecord()在取数据时,有可能获得空的数据集(也就是表中可能也没有记录了),supply方法在数据集为空时会休眠5分钟。休眠醒来通过this.getProductBlock()
再次检测数据集,如果数据集为空,则可能再次休眠。
这样会引发什么问题呢?
如果数据库中一直有未处理的记录,或者每隔一小段时间,就有未处理的数据入库,那么事情就没有问题,递归很快返回。但是如果一整天都没有新进来的未处理数据,那么由于是递归,那么递归的堆栈会累得非常高,消耗大量内存,到最后就可能OOM了。
下面的代码可以验证这种情景:
public class TestRecusive {
static int count = 10;
public static String doSomething() throws Exception {
Thread.sleep(10000);
if (count-- == 0) {
return "nothing";
}
return doSomething();
}
public static void main(String[] args) throws Exception {
doSomething();
}
看看,附件中,这个代码产生的堆栈。