Java 如何清理垃圾
有没有人举过这样的例子?它们是由垃圾收集器处理的吗?我正在使用Tomcat 6。javadoc说: “只要线程处于活动状态且线程本地实例可访问,每个线程都持有对其线程本地变量副本的隐式引用;线程退出后,其线程本地实例的所有副本都将接受垃圾收集(除非存在对这些副本的其他引用) 如果您的应用程序或(如果您谈论的是请求线程)容器使用线程池,这意味着线程不会消亡。如果需要,您需要自己处理线程局部变量。唯一干净的方法是调用Java 如何清理垃圾,java,tomcat,thread-local,Java,Tomcat,Thread Local,有没有人举过这样的例子?它们是由垃圾收集器处理的吗?我正在使用Tomcat 6。javadoc说: “只要线程处于活动状态且线程本地实例可访问,每个线程都持有对其线程本地变量副本的隐式引用;线程退出后,其线程本地实例的所有副本都将接受垃圾收集(除非存在对这些副本的其他引用) 如果您的应用程序或(如果您谈论的是请求线程)容器使用线程池,这意味着线程不会消亡。如果需要,您需要自己处理线程局部变量。唯一干净的方法是调用ThreadLocal.remove()方法 您可能希望清除线程池中线程的线程局部变
ThreadLocal.remove()
方法
您可能希望清除线程池中线程的线程局部变量有两个原因:
- 防止内存(或假设资源)泄漏,或
- 防止信息通过线程局部变量从一个请求意外泄漏到另一个请求
ThreadLocal
实例(而不是使用静态
变量来保存单实例),线程本地值不会被覆盖,并且会在每个线程的线程本地值
映射中累积。这可能会导致严重泄漏
假设您谈论的是在Web应用程序处理HTTP请求期间创建/使用的线程局部变量,那么避免线程局部泄漏的一种方法是使用您的Web应用程序的
ServletContext
注册ServletRequestListener
,并实现侦听器的requestdestromed
方法进行清理当前线程的线程局部变量
注意,在此上下文中,您还需要考虑从一个请求到另一个请求的信息泄漏的可能性。
< P>无法清除<代码>线程本地< /COD>值,除非从线程放在第一位的线程内(或者当线程是垃圾收集时-而不是用工作者线程的情况)。。这意味着您应该在servlet请求完成时(或在将AsyncContext传输到servlet 3中的另一个线程之前)注意清理ThreadLocal,因为在这一点之后,您可能再也没有机会进入特定的工作线程,因此,在服务器未重新启动的情况下,如果您的web应用程序未部署,将导致内存泄漏 进行此类清理的一个好地方是 如果您使用Spring,所有必要的连接都已经就绪,您可以简单地将内容放入请求范围,而不用担心清理它们(这会自动发生):以下是一些代码,当您没有对实际线程局部变量的引用时,可以从当前线程中清除所有线程局部变量。您还可以将其概括为清除其他线程的线程局部变量:
private void cleanThreadLocals() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i=0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
threadLocal.remove();
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
private void cleanThreadLocals(){
试一试{
//获取对当前线程的线程局部变量表的引用
Thread-Thread=Thread.currentThread();
字段threadLocalsField=Thread.class.getDeclaredField(“threadLocals”);
threadLocalsField.setAccessible(true);
对象threadLocalTable=threadLocalsField.get(线程);
//获取对数组的引用,该数组在
//当前线程的ThreadLocalMap
类threadLocalMapClass=Class.forName(“java.lang.ThreadLocal$ThreadLocalMap”);
Field tableField=threadLocalMapClass.getDeclaredField(“表格”);
tableField.setAccessible(true);
objecttable=tableField.get(threadLocalTable);
//ThreadLocalMap的键是WeakReference对象。此对象的referent字段
//是对实际ThreadLocal变量的引用
字段referentField=Reference.class.getDeclaredField(“referent”);
referencetfield.setAccessible(true);
for(int i=0;i
我想对这个问题给出我的答案,尽管这个问题已经很老了。我也被同样的问题困扰过(gson threadlocal没有从请求线程中删除),甚至在服务器内存耗尽时重新启动服务器(这太浪费时间了!!)
在设置为dev模式的javaweb应用程序的上下文中(服务器设置为在每次检测到代码更改时都会跳出,并且可能也在调试模式下运行),我很快了解到threadlocals可能非常棒,有时也会让人感到痛苦。我对每个请求都使用threadlocal调用。在调用内部。有时我还使用gson生成响应。我会将调用包装在过滤器中的“try”块中,并在“finally”块中销毁它
我所观察到的(我现在还没有数据支持)是,如果我对几个文件进行了更改,并且服务器在我的更改之间不断跳转,我会得到impati
private void cleanThreadLocals() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i=0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
threadLocal.remove();
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
public class MyObjectHolder {
private MyObject myObject;
public MyObjectHolder(MyObject myObj) {
myObject = myObj;
}
public MyObject getMyObject() {
return myObject;
}
protected void finalize() throws Throwable {
myObject.cleanItUp();
}
}
public class SomeOtherClass {
static ThreadLocal<MyObjectHolder> threadLocal = new ThreadLocal<MyObjectHolder>();
.
.
.
}
private static final MethodHandle s_getThreadLocals = initThreadLocals();
private static final MethodHandle s_expungeStaleEntries = initExpungeStaleEntries();
private static final ThreadLocal<Object> s_threadLocals = ThreadLocal.withInitial(() -> getThreadLocals());
public static void expungeThreadLocalMap()
{
Object threadLocals;
threadLocals = s_threadLocals.get();
try
{
s_expungeStaleEntries.invoke(threadLocals);
}
catch (Throwable e)
{
throw new IllegalStateException(e);
}
}
private static Object getThreadLocals()
{
ThreadLocal<Object> local;
Object result;
Thread thread;
local = new ThreadLocal<>();
local.set(local); // Force ThreadLocal to initialize Thread.threadLocals
thread = Thread.currentThread();
try
{
result = s_getThreadLocals.invoke(thread);
}
catch (Throwable e)
{
throw new IllegalStateException(e);
}
return(result);
}
private static MethodHandle initThreadLocals()
{
MethodHandle result;
Field field;
try
{
field = Thread.class.getDeclaredField("threadLocals");
field.setAccessible(true);
result = MethodHandles.
lookup().
unreflectGetter(field);
result = Preconditions.verifyNotNull(result, "result is null");
}
catch (NoSuchFieldException | SecurityException | IllegalAccessException e)
{
throw new ExceptionInInitializerError(e);
}
return(result);
}
private static MethodHandle initExpungeStaleEntries()
{
MethodHandle result;
Class<?> clazz;
Method method;
Object threadLocals;
threadLocals = getThreadLocals();
clazz = threadLocals.getClass();
try
{
method = clazz.getDeclaredMethod("expungeStaleEntries");
method.setAccessible(true);
result = MethodHandles.
lookup().
unreflect(method);
}
catch (NoSuchMethodException | SecurityException | IllegalAccessException e)
{
throw new ExceptionInInitializerError(e);
}
return(result);
}