论坛首页 Java企业应用论坛

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

浏览 12231 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-11-07   最后修改:2008-11-07
wangdi 写道
恩,也就是说造成这个OOM的是因为直接调用JDK1.4的run()方法。主要是不知道Thread里面的exit()方法是什么时候调用的,呵呵。。。
另外关于引用文章提到的线程池,对此有什么影响呢?是否像我说的那样:
----
就concurrent来说,线程池中线程执行完后,在默认的60s之后就会从线程池中remove,那么传入该线程的MyThread对象也应该在某个时候GC才对哦。
----
对线程的使用总是有些战战兢兢,真希望有一天用得得心应手。。。


exit()是private,在Thread内部也没有调用到,我猜测是jvm内部跟踪调用的。
你说的concurrent应该是Douge Lea的jdk1.4并发包吧,Douge Lea是并发专家,写出来的东西既然给了那么个接口应该是值的信赖的。没源码,看看源码吧,可能对execute(Thread)有特殊处理。不过还是推荐使用Runnable接口。


0 请登录后投票
   发表时间:2008-11-07  
呵呵,上源码,没做什么特殊处理,第一个任务来的时候,新增一个线程并执行它,第二个任务来的时候,如果没有线程在任务队列等待,则继续新增一个线程执行它,直到线程池满。如果有线程在任务队列等待,则让它取出去执行。
当一个线程有默认60s时间啥事没做,则把它从线程池中remove。
public void execute(Runnable command) throws InterruptedException {
    for (;;) {
      synchronized(this) { 
        if (!shutdown_) {
          int size = poolSize_;

          // Ensure minimum number of threads
          if (size < minimumPoolSize_) {
            addThread(command);
            return;
          }
          
          // Try to give to existing thread
          if (handOff_.offer(command, 0)) { 
            return;
          }
          
          // If cannot handoff and still under maximum, create new thread
          if (size < maximumPoolSize_) {
            addThread(command);
            return;
          }
        }
      }

      // Cannot hand off and cannot create -- ask for help
      if (getBlockedExecutionHandler().blockedAction(command)) {
        return;
      }
    }
  }


protected void addThread(Runnable command) {
    Worker worker = new Worker(command);
    Thread thread = getThreadFactory().newThread(worker);
    threads_.put(worker, thread);
    ++poolSize_;
    thread.start();
  }


protected synchronized void workerDone(Worker w) {
        threads_.remove(w);
        logger.info("Thread removed from thread pool.");
        if (--poolSize_ == 0 && shutdown_) {
            //disable new threads
            maximumPoolSize_ = minimumPoolSize_ = 0;
            //notify awaitTerminationAfterShutdown
            notifyAll();
        }
        // Create a replacement if needed
        if (poolSize_ == 0 || poolSize_ < minimumPoolSize_) {
            try {
                Runnable r = (Runnable) (handOff_.poll(0));
                //just consume task if shut down
                if (!shutdown_) {
                    //add unconditionally and keep the minimum pool size.
                    addThread(r);
                }
            } catch (InterruptedException ie) {
                return;
            }
        }
    }
0 请登录后投票
   发表时间:2008-11-07  
会不会被GC,只需要看还有没有被引用!!

所谓内存泄漏,就是忘记了在某个地方还有个引用。

firstTask_ = null; // enable GC  

这样的注释本质上就是错误的!!这是掩耳盗铃

对于concurrent,如果传入的还是有其他引用的线程对象,那也肯定不会被GC的!
0 请登录后投票
   发表时间:2008-11-07  
从你的源码给出来看,确实没有特殊处理,那么使用execute(Thread)还是会引起OOM的,换成实现Runnable接口了,有条件jrofile一下。
0 请登录后投票
   发表时间:2008-11-07  
timerri 写道
会不会被GC,只需要看还有没有被引用!!

所谓内存泄漏,就是忘记了在某个地方还有个引用。

firstTask_ = null; // enable GC  

这样的注释本质上就是错误的!!这是掩耳盗铃

对于concurrent,如果传入的还是有其他引用的线程对象,那也肯定不会被GC的!


同意,在这里根本就没有enable GC,只是firstTask_没有指向任何对象而已,原来的对象还是有被引用的:
Runnable task = firstTask_;
GC不会回收。

另外,就像上面朋友说的,调用run不会启动一个线程,我认为还是不能按照线程的生命周期来看它什么时候被回收。 如果没有调start(),或许线程连就绪状态还没有吧。
0 请登录后投票
   发表时间:2008-11-07  
呵呵,那个enable GC可不是我加的哦:)
调用run()不会启动线程,但是会在ThreadGroup里面把它加进去。。。
0 请登录后投票
   发表时间:2008-11-07   最后修改:2008-11-07
线程是不会被GC的,不走完线程的生命周期而直接显式给线程引用赋null是不会得到预期的GC结果的
0 请登录后投票
   发表时间:2008-11-07  
楼上正解!
0 请登录后投票
   发表时间:2008-11-08  
测试方法,不解释了。
public class ThreadDemo {
    public static void main(String[] args){
        ThreadOne one = new ThreadOne("ThreadOne");
        ThreadTwo two = new ThreadTwo();
        Thread.currentThread().getThreadGroup().list();
        one.run();
        two.run();
        try {
            //目的是保证one.run()和two.run()都已经执行了。
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Thread.currentThread().getThreadGroup().list();
        one.start();
        new Thread(two, "ThreadTwo").start();
        try {
            //目的是保证one.start()和new Thread(two, "ThreadTwo").start()都已经执行了。
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
        Thread.currentThread().getThreadGroup().list();
    }
}

class ThreadOne extends Thread {
    public ThreadOne(String name) {
        super(name);
    }

    public void run() {
        System.out.println("This is Thread one.");
    }
}

class ThreadTwo implements Runnable {
    public void run() {
        System.out.println("This is Thread two.");
    }
}
0 请登录后投票
   发表时间:2008-11-08  
测试代码:
public class ThreadGc {
	public static class LargeThread extends Thread {
		long[] data;
		public LargeThread(int size) {
			data = new long[size];
		}
		
		public void run() {
			// do nothing
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 1000000; i++) {
			new LargeThread(1000000);
		}
	}
}

看是否出现OOM?

在Jdk6和Jdk1.5.0_16下用Ubuntu64位系统测的结果是会回收的。
在Jdk1.4.2_16下用windows xp系统测的结果是没有回收的,会OOM。也可以打开-verbose:gc来验证
0 请登录后投票
论坛首页 Java企业应用版

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