线程池引起的jvm内存过大有关问题

线程池引起的jvm内存过大问题

之前的一个hbase表结构和rowkey规划不合理,我重新设计了一个新的hbase表,需要把旧表的数据写入到新表中,采用的方案是一个region一个region的倒数据,这样旧表的读是scan顺序读,新表的写是随机写,整体速度相对较快,读时采用单线程,写采用线程池,改进scan查询速度的caching配置设置为500,写线程池设置为100,在循环scan结果集时,每条数据的写新表的操作均会作为一个线程任务提交给线程池,由于没有充分的评估scan(产生数据)和写(消费数据)的速度,导致查询数据的速度比写的速度快,每次scan查询的数据均不能完全处理掉,因此导致线程池的队列不断的累积任务,在半小时内就导致消耗jvm内存到达16G(每个写操作均会持有scan出的数据,因此比较耗内存),发现问题后修改线程池大小为300,caching设置为200,并在每次scan查询时休眠100ms,这时基本上每次查询出的数据均会完全写入hbase,平均处理数据的速度由全速的10万条/s,降为8.8万/s,速度略有下降,但是不会因为任务堆积而导致jvm暴涨,最终出现OOM。

一般的业务场景可能提交任务到线程池的量或者任务占用的内存不会太大,而且线程池与队列并没有字面上的直接联系,因此程序猿很容易忽略队列最常见的生产和消费问题,导致程序在运行一段时间后就会出现莫名的OOM。