zoukankan      html  css  js  c++  java
  • Java线程引起的内存泄露问题浅析

    在实际的开发中我们经常会遇到需要使用线程的情况,我以前通常使用这两种方式

    第一种,线程使用内部类的方式包裹在实际的控制器内部,如下:
        class A {
                class B extends Thread {
                      @Override
                      public void run() {
    
                            super.run();
                      }
                }
          }

    第二种,线程使用外部类,控制器采用参数的方式传入,如下:

        class C {};
          class D extends Thread {
                private C ref;
                public D(C obj) {
                      ref = obj;
                }
    
                @Override
                public void run() {
                      super.run();
                }
          }
    其实,这两种常见的方式都是有问题的。下面就让我们来分析分析。
    第一种,我们知道内部类中是可以访问外部类的一切资源的,为什么?因为内部类中隐藏了一个指向外部类的指针(但是如果是静态类就没问题,因为静态类中不会有外部类的任何实例的指针),那么这就有一个问题,如果在B被回收之前,A是不会被回收的,而且这种情况是经常发生的,设想一下,如果A是一个运行在UI线程的类,比如说是一个listview的adapter类,而B是adapter类中负责通过网络请求图片的工作线程,那么由于联网需要的时间可能比较长,用户可能等待的不耐烦,推出了这个listview界面,跳转到别的界面去了,那么由于B没有运行完,那么B不可能被回收,那么B中的隐藏指针就仍然有效,那么意味着A还在被引用,那么A是不会被回收的,这时候如果A引用了大量的UI资源的话(这对于UI线程下运行的类来说是很可能的)那么会导致这些资源都不会被回收,这种情况下就可能会造成严重的内存泄露。
     
    第二种的原理其实跟第一种是一样的,不过这种形式引用看的更明白一些,道理跟第一种一样。
     
    那么,通常的作法是这样的
        class E extends Thread {
                private WeakReference<C> weakRef;
                public E(C obj) {
                      weakRef = new WeakReference<C>(obj);
                }
                
                @Override
                public void run() {
                      C obj = weakRef.get();
                      if (obj != null) doSomething();
                      super.run();
                }
          }
    这种方式使用弱引用来保持对UI线程中类的引用,就可以把UI线程和工作线程中对象的生命周期有效的隔离开, 这样如果UI线程不存在了,工作线程也就可以知道不必去更新UI了。
     
    下面给出一个例子
      1 package com.test.memtest;
      2 
      3 import java.lang.ref.WeakReference;
      4 import java.util.concurrent.TimeUnit;
      5 
      6 public class TestMain {
      7 
      8     class A {
      9         public void show() {
     10             System.out.println("Hello, I'm an instance of A");
     11         }
     12         
     13         public void run(int time) {
     14             new B(time).start();
     15         }
     16         
     17         class B extends Thread {
     18             private int count;
     19             
     20             public B(int count) {
     21                 this.count = count;
     22             }
     23             
     24             @Override
     25             public void run() {
     26                 for (int i = 0; i < count; i++) {
     27                     System.out.println(String.format("B has been running for %d seconds", i));
     28                     show();
     29                     try {
     30                         Thread.sleep(1000);
     31                     } catch (InterruptedException e) {
     32                         // TODO Auto-generated catch block
     33                         e.printStackTrace();
     34                     }
     35                 }
     36                 super.run();
     37             }
     38             
     39         }
     40     }
     41     
     42     class C {
     43         public void show() {
     44             System.out.println("Hey, I'm an instance of C");
     45         }
     46     };
     47     class D extends Thread {
     48         private C ref;
     49         public D(C obj) {
     50             ref = obj;
     51         }
     52         
     53         @Override
     54         public void run() {
     55             for (int i = 0; i < 10; i++) {
     56                 System.out.println(String.format("D has been running for %d seconds", i));
     57                 ref.show();
     58                 try {
     59                     TimeUnit.SECONDS.sleep(1);
     60                 } catch (InterruptedException e) {
     61                     // TODO Auto-generated catch block
     62                     e.printStackTrace();
     63                 }
     64             }
     65             super.run();
     66         }
     67     }
     68     
     69     class E extends Thread {
     70         private WeakReference<C> weakRef;
     71         public E(C obj) {
     72             weakRef = new WeakReference<C>(obj);
     73         }
     74         
     75         @Override
     76         public void run() {
     77             for (int i = 0; i < 10; i++) {
     78                 System.out.println(String.format("E has been running for %d seconds", i));
     79                 C ref = weakRef.get();
     80                 if (ref != null) {
     81                     ref.show();
     82                 } else {
     83                     System.out.println("C has been garbage collected");
     84                 }
     85                 try {
     86                     TimeUnit.SECONDS.sleep(1);
     87                 } catch (InterruptedException e) {
     88                     // TODO Auto-generated catch block
     89                     e.printStackTrace();
     90                 }
     91             }
     92             super.run();
     93         }
     94     }
     95     /**
     96      * @param args
     97      */
     98     public static void main(String[] args) {
     99 
    100         System.out.println("main thread start!");
    101         TestMain instance = new TestMain();
    102         instance.new A().run(10);
    103         instance.new D(instance.new C()).start();
    104         instance.new E(instance.new C()).start();
    105         System.gc();
    106         System.out.println("main thread over");
    107     }
    108 
    109 }
    输出结果如下:
    main thread start!
    B has been running for 0 seconds
    Hello, I'm an instance of A
    D has been running for 0 seconds
    Hey, I'm an instance of C
    main thread over
    E has been running for 0 seconds
    C has been garbage collected
    B has been running for 1 seconds
    Hello, I'm an instance of A
    D has been running for 1 seconds
    Hey, I'm an instance of C
    E has been running for 1 seconds
    C has been garbage collected
    B has been running for 2 seconds
    Hello, I'm an instance of A
    D has been running for 2 seconds
    Hey, I'm an instance of C
    E has been running for 2 seconds
    C has been garbage collected
    B has been running for 3 seconds
    Hello, I'm an instance of A
    D has been running for 3 seconds
    Hey, I'm an instance of C
    E has been running for 3 seconds
    C has been garbage collected
    B has been running for 4 seconds
    Hello, I'm an instance of A
    D has been running for 4 seconds
    Hey, I'm an instance of C
    E has been running for 4 seconds
    C has been garbage collected
    B has been running for 5 seconds
    Hello, I'm an instance of A
    D has been running for 5 seconds
    Hey, I'm an instance of C
    E has been running for 5 seconds
    C has been garbage collected
    B has been running for 6 seconds
    Hello, I'm an instance of A
    D has been running for 6 seconds
    Hey, I'm an instance of C
    E has been running for 6 seconds
    C has been garbage collected
    B has been running for 7 seconds
    Hello, I'm an instance of A
    D has been running for 7 seconds
    Hey, I'm an instance of C
    E has been running for 7 seconds
    C has been garbage collected
    B has been running for 8 seconds
    Hello, I'm an instance of A
    D has been running for 8 seconds
    Hey, I'm an instance of C
    E has been running for 8 seconds
    C has been garbage collected
    B has been running for 9 seconds
    Hello, I'm an instance of A
    D has been running for 9 seconds
    Hey, I'm an instance of C
    E has been running for 9 seconds
    C has been garbage collected
     
    我们可以很清楚的看出,在线程B,D运行期间,他们引用的对象都没有得到回收,而线程E引用的对象在gc后得到了回收。
    补充,在线程中设置监听器的情况有一些麻烦的情况,留在下一篇文章中讨论。

     

  • 相关阅读:
    JVM-程序编译与代码晚期(运行期)优化
    JVM-程序编译与代码早期(编译期)优化
    JVM-字节码执行引擎
    JVM-类加载机制
    JVM-字节码指令
    JVM-class文件完全解析-属性表集合
    zabbix配置邮箱报警功能
    Linux Shell 返回值之 PIPESTATUS
    SSH远程登录原理
    Zabbix监控USG6300防火墙及交换机
  • 原文地址:https://www.cnblogs.com/yueang/p/2754339.html
Copyright © 2011-2022 走看看