内存泄漏事故(二)线程的中断不可信任【重要】配合volatile强制回收子线程成员变量

1

Map<k, list>

not good:

map.remove(k)

如果这时有其他指针指向list,则list无法释放

 

good:

map.get(k).clear()

map.remove(k)

即使这是有其他指针指向list,导致list无法释放,但是这个list是空的,泄漏的后果不严重

 

2 线程的中断不可信任

2.1 要确保清理到位给予线程的引用

怎么做?见3

2.2 避免无法从外部清理线程的资源

尽量不要用局部变量接收大对象,方法如果block了资源会被局部metho hold住,外部也没办法接触;

ex:

func(List list) {

  List x = list;

  for(Object o : x) {

    do sth(o); // blocked, 如果这个do sth方法没有办法被打断,那么这个局部变量x会hold住一个list造成泄漏

  }

}

用成员变量,+volatile,外部线程强制解绑

 

 注意volatile修饰ref

 

可以看到确实可以确实可以强制回收,主线程的clear把子线程的成员变量强行刷成null

 

3 细节

 

再改一版

  

3.1 future task cancel

3.1.1 如果能进cancellation(理论上不会出现,因为没有对futureTask做cancel),说明子线程future一定已经接收了cancel的指令,至于是中断中还是中断完了,是否完成finally未知,因此要手动clear

子线程既已在中断中或中断完,则无需再次interrupt

而本线程无需interrupt一下,因为本线程并未接收到cancel或interrupte,因为如果接收了任一,则会进入Interrupted

3.1.2 习惯上必须设置timeout,避免本线程一直在那里等,timeout后清理掉资源和stop子线程

3.1.3 InterruptedException,说明有人在外边要stop本线程,那么清理掉资源,往下传递stop指令, future task cancel (二)向下传递中断

同时因为是进的InterruptedException,重新设置一下旗标

3.1.4 从future。get方法,如果不是cancellation和interrupted的其他异常,则fianally一定已经跑过了

3.1.5 其他exception也要clear一下,避免非子线程地方出现异常,但是资源已经给了子线程的情况

 

3.2 new操作时调用当前线程的类加载器,还是调用方的类加载器 (四)完美证明用例

当前线程类加载器,并不是当前线程的类由当前线程的类加载器加载,别搞错了

 

3.3 对3.1 所引用的那篇文章小结下

3.3.1 对子线程interrupt,父线程继续get,get什么取决于子线程怎么写的

3.3.2 对子线程cancel,父线程进cancellation

3.3.3 对子线程cancel,马上对父线程cancel,父线程进interrupted

3.3.4 对子线程cancel,隔一段时间对父线程cancel,父线程进cancellation

 

posted on 2024-08-02 00:24  silyvin  阅读(25)  评论(0)    收藏  举报