论坛首页 Java企业应用论坛

无法回帖啊,,再关于线程误用导致内存泄露的问题

浏览 12215 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-11-07   最后修改:2008-11-07
基本同:http://www.iteye.com/topic/11217?page=1
问题主要是关于Thread和Runnable的。在我们项目里面用一般的Runnable不会有问题,但是用Thread,时间长了就会oom。
1、当一个类继承Thread,不调用它的run()方法而是调用start()方法的话,使用完后它能被GC吗?
public class MyThread extends Thread{   
    public void run();{   
        //do something.   
    }   
}   
public static void main(String[] args){   
    Thread t = new MyThread();
    t.run();
    //do another thing.   
}   


2、如果能被回收,如果这个线程是通过concurrent的线程池调用的话,情况还是这样吗?
pooledExecutor.execute(new MyThread());

在concurrent的线程池中,执行传入的Runnable,是直接执行它的run方法,而不是把这个Runnable新起一个线程来执行:
protected class Worker implements Runnable {
    protected Runnable firstTask_;

    protected Worker(Runnable firstTask) { firstTask_ = firstTask; }

    public void run() {
      try {
        Runnable task = firstTask_;
        firstTask_ = null; // enable GC

        if (task != null) {
          task.run();
          task = null;
        }
        
        while ( (task = getTask()) != null) {
          task.run();
          task = null;
        }
      }
      catch (InterruptedException ex) { } // fall through
      finally {
        workerDone(this);
      }
    }
  }


在上面的文章中,有位兄台的回复:
引用
此处thread 不会被回收我想情况应该是线程池的缘故,app server会把线程存入池中优化性能,在池中的线程是不会被gc的, servlet执行完毕后该servlet所在线程会被线程池回收,所以不会被gc,所以t 肯定也不会被gc。

就concurrent来说,线程池中线程执行完后,在默认的60s之后就会从线程池中remove,那么传入该线程的MyThread对象也应该在某个时候GC才对哦。为啥,它就不GC呢?

....日本人,java code里面的code没办法加高亮。
   发表时间:2008-11-07  
你是如何得知它没有被gc的呢?
0 请登录后投票
   发表时间:2008-11-07  
LZ,还是把线程的概念想清楚了, 再来问吧。 Thread和Runnable 这2个东西的区别在那儿你不知道的话, 估计你很难明白。

    pooledExecutor.execute(new MyThread()); 

执行是什么, 要看清楚, 为什么泄露我不知道, 但是, pooledExecutor接受的Runnable的接口, 不使用THREAD接口吧?
0 请登录后投票
   发表时间:2008-11-07  
sdh5724 写道
LZ,还是把线程的概念想清楚了, 再来问吧。 Thread和Runnable 这2个东西的区别在那儿你不知道的话, 估计你很难明白。

    pooledExecutor.execute(new MyThread()); 

执行是什么, 要看清楚, 为什么泄露我不知道, 但是, pooledExecutor接受的Runnable的接口, 不使用THREAD接口吧?


呵呵,兄台大意了,JDK 1.4源码:
public class Thread implements Runnable 

也就是说:Thread也是Runnable
0 请登录后投票
   发表时间:2008-11-07  
timerri 写道
你是如何得知它没有被gc的呢?

没有被GC是OOM之后分析出来的。。。这个结论我相信没错,因为除了我们这儿遇到之外,我引用的帖子里面也谈到了这点。
0 请登录后投票
   发表时间:2008-11-07  
这个问题会跟jdk版本有关,你引用的帖子里的jdk的确把thread加入到了thread group里,但是在新的jdk1.6中已经改变了这种方式,变成了仅仅计数而不添加到group里。

以这种方法实现的thread,无论是否start都将被正确收集。
如果你确保你的jdk版本没有问题,那么oom可能会是别的问题引起
0 请登录后投票
   发表时间:2008-11-07   最后修改:2008-11-07
timerri 写道
这个问题会跟jdk版本有关,你引用的帖子里的jdk的确把thread加入到了thread group里,但是在新的jdk1.6中已经改变了这种方式,变成了仅仅计数而不添加到group里。

以这种方法实现的thread,无论是否start都将被正确收集。
如果你确保你的jdk版本没有问题,那么oom可能会是别的问题引起


采用引用计数,有无链接给出?还是你的猜测?我看了下jdk6中的Thread源码,改了一个地方,将

group.add(this)


这行从构造函数中移到了start方法:


 public synchronized void start() {
        /**
	 * This method is not invoked for the main method thread or "system"
	 * group threads created/set up by the VM. Any new functionality added 
	 * to this method in the future may have to also be added to the VM.
	 *
	 * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);  //这里
        start0();
        if (stopBeforeStart) {
	    stop0(throwableFromStop);
	}
    }


0 请登录后投票
   发表时间:2008-11-07  
timerri 写道
这个问题会跟jdk版本有关,你引用的帖子里的jdk的确把thread加入到了thread group里,但是在新的jdk1.6中已经改变了这种方式,变成了仅仅计数而不添加到group里。

以这种方法实现的thread,无论是否start都将被正确收集。
如果你确保你的jdk版本没有问题,那么oom可能会是别的问题引起

我的JDK是1.4,在构造方法里面调用的
private void init(ThreadGroup g, Runnable target, String name,long stackSize)
方法确实把当前对象加到了ThreadGroup里面。。。
g.add(this);

我想知道就是,这儿在构造方法里面添加到ThreadGroup里面,但是却没有调用start()方法而是调用run()方法会造成oom吗?
0 请登录后投票
   发表时间:2008-11-07   最后修改:2008-11-07
wangdi 写道
timerri 写道
这个问题会跟jdk版本有关,你引用的帖子里的jdk的确把thread加入到了thread group里,但是在新的jdk1.6中已经改变了这种方式,变成了仅仅计数而不添加到group里。

以这种方法实现的thread,无论是否start都将被正确收集。
如果你确保你的jdk版本没有问题,那么oom可能会是别的问题引起

我的JDK是1.4,在构造方法里面调用的
private void init(ThreadGroup g, Runnable target, String name,long stackSize)
方法确实把当前对象加到了ThreadGroup里面。。。
g.add(this);

我想知道就是,这儿在构造方法里面添加到ThreadGroup里面,但是却没有调用start()方法而是调用run()方法会造成oom吗?



肯定,你给出的帖子已经说明了这种情况。直接调用run()并没有启动一个线程,jvm不会跟踪这个对象的生命周期,正常情况下线程退出后会调用private void exit()方法从ThreadGroup中remove本对象,但是调用run()就享受不到这个擦屁股服务。不过在jdk6的这个小小调整后应该没有这个问题了。

 

 /**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
    private void exit() {
	if (group != null) {
	    group.remove(this);
	    group = null;
	}
        ...
     }
 
0 请登录后投票
   发表时间:2008-11-07  
恩,也就是说造成这个OOM的是因为直接调用JDK1.4的run()方法。主要是不知道Thread里面的exit()方法是什么时候调用的,呵呵。。。
另外关于引用文章提到的线程池,对此有什么影响呢?是否像我说的那样:
----
就concurrent来说,线程池中线程执行完后,在默认的60s之后就会从线程池中remove,那么传入该线程的MyThread对象也应该在某个时候GC才对哦。
----
对线程的使用总是有些战战兢兢,真希望有一天用得得心应手。。。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics