jdbc分配内存分析

jdbc查询数据库时,内存是怎么分配的?
对这个问题感兴趣是因为在一次项目中,经常碰到多线程查询导出oracle数据时,发生oom。但是websphere已经设置到2G,情况依然时有发送,也没有内存泄露的情况发生。最后调试,发现fetchSize设置过大为5000,每次查询数据时,不管实际返回多少条数据,都会分配5000*每行大小的内存,最后调小fetchSize,问题解决(调至分页查询时的页大小)。



分配内存猜想可能有以下几种方式:
1.jdbc查询数据库根据加载的实际数据大小,在jvm中分配内存,以性能换线程

2.jdbc查询数据库时,提前根据数据库中表结构,预加载内存,以内存换性能
现在一般都是通过jdbc接口操作数据库,而fetchSize是jdbc的一个属性,所查询数据库时,一般都是预分配内存

3.jdbc查询的结果集放在ResultSet里面,其设置到java对象的map或pojo中是引用buffers还是复制相同的令一份
猜想应该不是引用的方式,而是创建新对象去接收,要不然jdbc的connection关闭,buffers就被回收了



分配内存的方式,不同的厂商有不同的处理方式:
以oracle为例,其采用了第二种方式,
例如
create table (id number(10),name varchar2(40),birth date);

查询数据库时,通过Statement或PrepareStatement来执行的,每个Statement会持有2个buffers,这些buffers又在一个叫做Implicit Statement Cache的cache中。2个buffers一个为char[],另一个为byte[]。char[]存放varchar2,char等数据类型,byte[]存放其他类型。
id number(10) 占用22bytes
birth date     占用22bytes
name varchar2(40)  占用40*2bytes

所有在查询数据库之前,分配内存数为:
22+22+40*2=124bytes

这只是一行的数据,Oracle JDBC默认是取十行,那分配的大小就是1240 bytes了。
如果将fetchSize设置为5000,那么就有500M了,对于jvm来说,是惊人的



而对于mysql数据库驱动,fetchSize默认是查询全部的数据,如果查询数据过大,需要调小fetchSize,通过ResultSet滚动读取数据



执行一个select语句,不是只查询一次数据库。




oracle jdbc 内存管理
http://solitary.iteye.com/blog/1431704

Fetch Size 与 JDBC 内存管理
http://allenn.cn/articles/2016-12/2016-12-13-fetchsize-jdbc-memory/

提高JDBC应用程序的性能
http://www.voidcn.com/blog/hwctl/article/p-4547155.html

猜你喜欢

转载自newjava-sina-cn.iteye.com/blog/2383756
今日推荐