由于 Tomcat 的连接池中的空闲数据库连接导致 OOM

OOM due to Idle DB connections in Tomcat's ConnectionPool

我正在使用 Tomcat 8.0.27、OpenJDK 8 更新 71 和 Oracle 11.2.0.3.0。驱动程序版本是 Oracle Database 11g 第 2 版 (11.2.0.3)。我遇到了 OOM 错误。

我深入到连接池对象,其中最大的对象是空闲连接列表:

放大空闲连接列表显示 oracle.jdbc.driver.PhysicalConnection$BufferCacheStore:

占用的内存

我的假设是这些缓冲区是由以前的连接持有者分配的,并且由于我的池配置允许容纳最多 30 个空闲连接,它们在达到空闲限制之前不会释放。

我的数据库池配置是:

  <bean id="dataSourcePoolProperties" class="org.apache.tomcat.jdbc.pool.PoolProperties">
                <property name="driverClassName">
                    <value>${db.driverClass}</value>
                </property>
                <property name="url">
                    <value>${db.url_prefix}:@${db.host}:${db.port}:${db.sid}</value>
                </property>
                <property name="username">
                    <value>${db.user}</value>
                </property>
                <property name="password">
                    <value>${db.password}</value>
                </property>
                <property name="maxActive">
                    <value>50</value>
                </property>
                <property name="maxIdle">
                    <value>30</value>
                </property>
                <property name="initialSize">
                    <value>10</value>
                </property>
                <property name="testOnBorrow">
                    <value>true</value>
                </property>
                <property name="testOnReturn">
                    <value>true</value>
                </property>
                <property name="validationQuery">
                    <value>select 1 from dual</value>
                </property>
                <property name="name">
                    <value>Main DataSource</value>
                </property>
                <property name="jmxEnabled">
                    <value>true</value>
                </property>
                <property name="logValidationErrors">
                    <value>true</value>
                </property>
            </bean>

我知道 Oracle 的驱动程序根据可能的最大查询大小分配缓冲区。检查它们的内容发现那里有许多零。

编辑 1:

Oracle的驱动jar文件在WEB-INF/lib文件夹下,tomcat-jdbc.jar在CATALINA_HOME/lib文件夹下。我知道这对于重新部署可能会有问题,但我们不这样做。

您能建议一种消除内部驱动程序缓冲区的方法吗?

显然,OOM 是由于我们对驱动程序获取大小、每次获取要检索的行数所做的更改引起的。随着每一个的大小 列和行数,驱动程序可以计算单次提取中返回的数据的绝对最大大小。这可能是导致预分配缓冲区增长的原因。

仔细阅读 Oracle 的驱动程序文档后发现

"11.2 驱动程序具有比 11.1.0.7.0 更复杂的缓冲区缓存。此缓冲区缓存具有 多个桶。桶中的所有缓冲区都具有相同的大小,并且该大小是预先确定的。 当第一次执行 PreparedStatement 时,驱动程序从桶中获取缓冲区 保存将保存结果的最小大小的缓冲区。如果桶中没有缓冲区,则 驱动程序分配一个与桶对应的预定义大小的新缓冲区。当一个 PreparedStatement 关闭,缓冲区返回到它们适当的桶中。由于缓冲区 用于一系列大小要求,缓冲区通常比 最低要求。"

回滚获取大小参数后,OOM 错误消失了。