是否值得在 Filter 中清理 ThreadLocals 以解决与线程池相关的问题?

Posted

技术标签:

【中文标题】是否值得在 Filter 中清理 ThreadLocals 以解决与线程池相关的问题?【英文标题】:Is it worth cleaning ThreadLocals in Filter to solve thread pool-related issues? 【发布时间】:2011-06-30 13:39:19 【问题描述】:

简而言之 - tomcat 使用线程池,因此线程被重用。一些库使用ThreadLocal 变量,但不清理它们(使用.remove()),所以实际上它们将“脏”线程返回到池中。

Tomcat 具有在关闭时检测这些东西并清理线程本地变量的新功能。但这意味着线程在整个执行过程中都是“脏的”。

我能做的是实现一个Filter,在请求完成后(线程返回到池中),清理所有ThreadLocals,使用code from tomcat(那里的方法称为@ 987654326@).

问题是,值得吗?两个优点:

防止内存泄漏 防止库的不确定行为,假设线程是“新的”

一个缺点:

该解决方案使用反射,因此可能会很慢。当然,所有反射数据 (Fields) 都会被缓存,但仍然如此。

另一种选择是将问题报告给不清理其线程本地变量的库。

【问题讨论】:

【参考方案1】:

我会通过向库开发人员报告问题的途径,原因有两个:

这将有助于其他想要使用相同库但缺乏技能/时间来发现这种可怕的内存泄漏的人。 帮助库的开发人员构建更好的产品。

老实说,我以前从未见过这种类型的错误,我认为这是一个例外,而不是我们应该注意的事情,因为它经常发生。你能分享一下你在哪个图书馆看到过这种行为吗?

附带说明,如果仍然附加了 ThreadLocal 变量,我不介意在开发/测试环境中启用该过滤器并记录严重错误。

【讨论】:

这不仅仅是一个库,这就是问题所在。清理线程局部变量似乎很少进行。 未能清理 ThreadLocal 通常不是内存泄漏 - 例如,如果您使用 ThreadLocal 与 Integer 占用的空间相比,Integer 占用的空间可以忽略不计线程的其余资源。如果库在每个请求开始时假定 ThreadLocal 为空,这只是一个问题。 我想你弄糊涂了,我们不是在谈论与存储内容相关的本地线程的大小,而是当 Web 应用程序运行时它如何产生(整个类加载器的)内存泄漏已卸载。此外,仅存储一个简单类的场景并不常见。通常你会有一个框架,比如spring,把一些对象放在线程本地。【参考方案2】:

理论上,这似乎是个好主意。但是,我可以看到您可能想要这样做的一些情况。例如,一些与 xml 相关的技术有一些重要的设置成本(如设置 DocumentBuilders 和 Transformers)。如果你在你的 web 应用程序中做了很多 很多,那么将这些实例缓存在 ThreadLocals 中可能是有意义的(因为这些实用程序通常不是线程安全的)。在这种情况下,您可能不想在请求之间清除这些内容。

【讨论】:

即使有一些副作用,我认为也不应该那样滥用。 @Bozho,你为什么认为这是一种滥用?它更像是一个廉价的对象池。 因为您永远无法确定给定的库是否能正确执行所有操作。安全总比后悔好;)【参考方案3】:

如果您认为线程的脏污实际上可能会导致问题,那么这是明智的做法。尽可能避免问题。

使用 threadlocals 可能是库的不良行为,您当然应该向作者报告,但遗憾的是,现在,由您来处理它。

我不会太担心性能。反射的慢一点是元数据查找;一旦你有一个 Field 对象,然后使用它会相当快,并且随着时间的推移变得更快 - AIUI,它通过对 JVM 进行本机调用开始工作,但在使用了一些次数后,它会生成用于访问的字节码,这然后可以编译为本机代码,优化,内联等,因此它不应该比直接字段访问慢很多。不过,我认为 Tomcat 代码不会跨请求重用 Field 对象,所以如果你想利用它,你必须编写自己的清理代码。无论如何,性能成本将远远小于与请求相关的 IO 成本。

【讨论】:

以上是关于是否值得在 Filter 中清理 ThreadLocals 以解决与线程池相关的问题?的主要内容,如果未能解决你的问题,请参考以下文章

是否在 PDO oveekill 中清理数据 + 参数化? [复制]

Yii1 - 在之前的操作中清理GET参数

数据清理

添加filter_var后,PHP代码在SQL表中插入空值

JS常用代码片段2-值得收藏

JS常用代码片段2-值得收藏