0

我想分享一个奇怪的例子。在生产中,我们的应用程序抛出 OOM 异常,我们进行了堆转储并开始分析,后来我们发现 com.mchange.v2.c3p0.stmt.PerConnectionMaxOnlyStatementCache 实例存在问题。该对象的大小约为堆大小的 50%。该应用程序正在与数十亿用户一起运行,并且服务器一次又一次地停机。

此应用程序在 tomcat 上运行,其中 tomcat 连接器允许最大 300 个并发请求,以下是 c3p0 配置。

jdbc.hibernate.c3p0.minPoolSize=2
jdbc.hibernate.c3p0.maxPoolSize=150
jdbc.hibernate.c3p0.maxIdleTime=0
jdbc.hibernate.c3p0.maxStatementsPerConnection=50
jdbc.hibernate.c3p0.numHelperThreads=6

从堆监控工具中,我们收到以下消息

由“org.apache.catalina.loader.WebappClassLoader @ 0x82f1c58”加载的“com.mchange.v2.c3p0.stmt.PerConnectionMaxOnlyStatementCache”实例占用 72 970 824 (57,75%) 个字节。内存在“org.apache.catalina.loader.WebappClassLoader @ 0x82f1c58”加载的“com.mchange.v2.c3p0.stmt.PerConnectionMaxOnlyStatementCache”的一个实例中累积

请告知:-这个实例占用如此大内存的原因是什么?我们是否使用正确的 c3p0 配置运行?对于负载较重的应用程序,推荐的配置是什么?

提前致谢

4

3 回答 3

2

您已设置 maxStatementsPerConnection=50 和 maxPoolSize=150。这意味着语句缓存在任何时候可能有多达 7500 个打开的语句,包括驱动程序与语句关联的任何资源的内存占用。您基本上是在要求 c3p0 使用大量内存,理论上内存成本低于准备语句的性能成本。

首先,这可能根本不是真的,在这种情况下,语句缓存通常是失败者,你不应该使用它。您应该将 maxStatements 和 maxStatementsPerConnection 都设置为零来测试您的应用程序是否真的从语句缓存中受益(如果您还没有的话)。对于在 PreparedStatement 对象中缓存大量解析和准备的驱动程序,语句缓存可以提供很大帮助。但是您需要在缓存的内存占用和预缓存语句的性能优势之间进行权衡。很明显,即使语句缓存对您的性能有所帮助,您也已经超出了收益超过成本的地步。

在你的应用程序中,这 150 条准备好的语句中有多少是经常使用的?你能不能让这个数字更小,最好更小,期待更不常用的语句会从缓存中退出并很好地摆脱它们?或者,您可以不理会该数字,但将 maxStatementsPerConnection 与全局 maxStatements 设置结合起来(设置为小于您当前使用的隐式 7500 的值)。如果结合 maxStatementsPerConnection 和 maxStatements,当池较小时,每个 Connection 最多可以有 maxStatementsPerConnection,但是随着池变大并且内存占用成为危险,全局 Statement 限制将导致最近使用较少的 Statements 启动退出缓存以保留内存。

我希望这个对你有用!

于 2012-07-17T22:10:57.507 回答
0

这是因为你给了maxIdleTime=0

将 maxIdleTime 设置为非零值允许 C3P0 从池中删除连接并释放数据库资源。

当 maxIdleTime 设置为 0 时,这永远不会发生

.

所以我相信你的连接都没有从池中删除。这就是为什么它的堆大小变得很大的原因。

如需更多参考,请单击此处

于 2013-06-24T13:25:30.053 回答
-1

尝试使用BoneCP作为高性能连接池,它解决了 c3p0 和 Apache DBCP 的许多面向性能的问题。

于 2012-07-17T08:40:29.433 回答