本帖最后由 binghc 于 2012-07-08 13:41:35 编辑

解决方案 »

  1.   

    API里面有句:
    对 Timer 对象最后的引用完成后,并且 所有未处理的任务都已执行完成后,计时器的任务执行线程会正常终止(并且成为垃圾回收的对象)。但是这可能要很长时间后才发生。楼主在run函数最后加一句 System.gc();  试试
      

  2.   

    编码逻辑形成了类似递归调用的情况。JVM的垃圾回收,回收的是你程序中,不再引用的对象;而对于程序中被引用(正在使用)的对象,JVM是不做回收处理的。楼主的MyTimerTask 类,其对象首次被实例化(分配内存),是在主线程(的main方法)中,
    之后,交由Timer进行(run方法的)的方法调用。这时,该MyTimerTask对象,被Timer所持有,由于schedule方法是重复执行的方法,后台会有一个子线程持有Timer对象,所以,Timer对象尽管在主线程中没被引用,但是,它会被后台子线程所引用,而不会得到垃圾回收。之后,当Timer被触发,调用MyTimerTask的run方法时,run方法又会创建Tiemr实例,生成子线程持有本身而不释放。程序的最终结果,就是在程序的后台,不停地创建Timer子线程,并且,这些Timer的实例(对象)得不到垃圾回收,当然,Timer提交的任务对象(MyTimerTask对象)被Tiemr持有而不会被垃圾回收,最终,随着时间的推移,JVM内存不足,表现的现象就是内存泄露。
      

  3.   

    回复 #4楼
    那请问哥们,
    new Timer().schedule(new MyTimerTask(), 0+count*2);
    这句代码创建出来的Timer线程调度后,
    new MyTimerTask()这个对象又被谁引用么?既然创建了很多Timer后台线程为什么我手动掉gc能清理垃圾这些Timer线程(因为空闲内存没继续减少,所以可以判断Timer对象也被回收了)最后,怎么不自己手动调用gc,让JVM自动回收垃圾
      

  4.   

    纠正一下,Timer.schedule(TimerTask task, long delay)这个方法中,task对象只会被调用一次。
    是延时调用而不是重复调用,刚才,没看清楚代码。
    重复调用的方法是:Timer.schedule(TimerTask task, long delay, long period),最后那个参数是重复调用的周期。延时调用的task对象,当调用完成之后,就不会被Timer的线程实例所持有了,这时,可以被垃圾回收。
    由于task对象可以被回收,那么,里面产生的Timer对象,也会有被回收的可能。程序设计当中,是允许程序员进行gc操作的,但是,gc操作只是通知JVM进行垃圾回收,至于JVM是否真的进行垃圾回收,要根据JVM的回收策略进行触发。
    所以说,楼主可以手动gc,这没什么错的地方。最后,楼主 Exception in thread "Timer-3976" 
    java.lang.OutOfMemoryError: unable to create new native thread
    这个日志的信息,是表示的内存不足了,无法创建更多的线程实例。
    这里,我想多说一句,我们的程序,应该尽量的提高线程的利用。一个程序,没必要创建将近4千个线程来做事情吧,我们可以创建尽量少的线程,(比如2~4个)来处理这些task,这些task只是调用的时间不同,而大多数情况下,不需要并发处理,即使要并发处理,也不用变态到几千个同时来。
      

  5.   

    由于 Timer 和 TimeTask 存在一定的缺陷。从 JDK 1.5 开始并发包中增加了 ScheduledExecutorService 接口,因此从 JDK 1.5 开始就没有理由再去使用 Timer 和 TimeTask 了。
      

  6.   

    楼主,两个问题请注意:
    1、内存分配越多,所能创建线程数越少;
    2、线程数太多,系统运行能效反而下降。关于第一个问题,可以参见:
      http://sesame.iteye.com/blog/622670关于第二个问题:
      不要滥用线程,如果你想使用大规模任务处理的话,用线程池更好些。
      

  7.   

    #8楼 的哥们,你的头像我很喜欢,呵呵还有一个问题啊,Timer这个计时线程怎么手动关闭它呀
      

  8.   

    可以用 cancel()不过还是要多听听 7楼火龙果 的建议。
      

  9.   

    当然,我现在只是用原生的,就像在开发中不会用synchronized,而是用已经
    java.util.concurrent 这个包里已经分装好功能更强大的多线程并发包