Rob*_*ume 8 java memory-leaks thread-local number-formatting sonarqube
自 2019 年 8 月 21 日起可用的声纳规则 ( squid:S5164 / RSPEC-5164 ) 要求在不再使用时清理“ThreadLocal”变量。因此,让我们学习以下类(兼容 JDK6):
public class ThreadLocalExample {
private static final ThreadLocal<NumberFormat> formats = new ThreadLocal<NumberFormat>() {
@Override
protected NumberFormat initialValue() {
final NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
nf.setGroupingUsed(false);
return nf;
}
};
public static NumberFormat getFormatter() {
return formats.get();
}
}
Run Code Online (Sandbox Code Playgroud)
声纳报告一个重要的错误的ThreadLocal声明,在以下的说明:
不再使用时应清除“ThreadLocal”变量
ThreadLocal一旦持有线程不再活动,变量应该被垃圾收集。重新使用持有线程时可能会发生内存泄漏,使用线程池的应用程序服务器就是这种情况。为避免此类问题,建议始终
ThreadLocal使用remove()清除当前线程的ThreadLocal变量值的方法清理 变量。
现在,我采用这种ThreadLocal方法是为了NumberFormat尽可能多地重用实例,避免每次调用创建一个实例,所以我认为如果我remove()在代码中的某个地方调用,我将失去这个解决方案的所有优点。我错过了什么吗?非常感谢。
声纳就在这里。
每个线程都有自己的ThreadLocal状态,因此有自己的NumberFormat.
因此,在一般情况下,不从状态中清除数据可能是不希望的,因为线程可能被重用(由服务器回收)并且为先前客户端赋值的状态可能与当前客户端不一致。
例如,某些客户端可以具有 format US,其他客户端可以具有 format FR,等等...除了某些线程可以实例化 ThreadLocal 类之外,其他线程则不能。但是,如果不清理状态,状态仍将为可能不需要它们的线程使用内存。
好吧,在您的代码中,ThreadLocal由于您为任何实例设置了状态,所以状态不存在可变性,因此不可能出现不一致的风险,只是内存“浪费”。
现在,我采用了 ThreadLocal 方法,以便尽可能地重用 NumberFormat 实例,避免每次调用创建一个实例
您可以ThreadLocal根据线程请求重用状态。
因此,如果有 50 个线程,则有 50 个状态。
在 Web 应用程序中,服务器将客户端 HTTP 请求映射到一个线程。
因此,您不会仅在 1 个 http 请求的范围内创建格式化程序的多个实例。这意味着如果您在请求处理中使用格式化程序一两次,缓存ThreadLocal不会带来很大的价值。但如果你用的多了,用起来还是有意义的。
所以我想如果我在代码中的某个地方调用remove(),我将失去这个解决方案的所有优点
如果在请求remove()处理完成后进行调用,则不会影响性能。您不会失去任何优势,因为您可能在请求范围内使用格式化程序数十次,并且只有在最后才会被清理。
您在 servlet 规范中有请求侦听器:
https://docs.oracle.com/javaee/7/api/javax/servlet/ServletRequestListener.html。
你可以在void requestDestroyed(ServletRequestEvent sre).
| 归档时间: |
|
| 查看次数: |
1880 次 |
| 最近记录: |