您的位置:

tombstones

tombstones(墓碑)是指应用程序中已被“杀死”的进程的残留痕迹。这些残留物包括被释放的内存、打开的文件和临时文件、未释放的锁等。由于这些残留物占用着系统资源,会导致系统性能问题和安全问题。因此,tombstones是Android开发中需要注意的问题。

一、内存泄漏

内存泄漏是指程序中已不再使用的内存没有被回收的问题。在Android中,如果程序未正确释放资源,就会导致tombstones的产生。当进程被杀死时,这些未释放的资源将成为应用程序的tombstones。

下面是一个内存泄漏的示例:

public class MyActivity extends Activity {
    private static List mLeakedList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (int i = 0; i < 10000; i++) {
            Object obj = new Object();
            mLeakedList.add(obj);
        }
    }
}


在这个示例中,我们创建了一个静态的ArrayList用于存储Object,并在onCreate方法中往里面添加了10000个Object。由于我们未在Activity销毁时清空ArrayList,这些Object将无法被回收,从而导致内存泄漏。

二、文件未关闭

在Android应用程序中,打开的文件应该在使用后被关闭,否则会导致文件句柄泄漏。当进程被杀死时,这些未关闭的文件将成为应用程序的tombstones。文件句柄泄漏会导致系统资源的浪费,降低系统性能。

下面是一个文件未关闭的示例:

public void readFile() {
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new FileReader("file.txt"));
        String line;
        while ((line = reader.readLine()) != null) {
            // Do something with the line
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们使用BufferedReader和FileReader来读取文件内容。然而,在finally块中,我们没有判断reader是否为空就直接关闭它,这会导致NullPointerException。正确的做法应该是判断reader是否为空再进行关闭操作。

三、锁未释放

在Android应用程序中,我们经常使用锁来实现线程同步。当锁未被正确释放时,会导致应用程序的tombstones。这会导致系统资源的浪费,对系统性能造成影响。

下面是一个锁未释放的示例:

public class MyActivity extends Activity {
    private Object mLock = new Object();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (mLock) {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        synchronized (mLock) {
            // Do something
        }
    }
}

在这个示例中,我们在onCreate中创建了一个新的线程,并在其中使用synchronized关键字锁住了一个对象。在onDestroy方法中,我们再次对同一个对象进行了锁定。然而,由于线程代码中使用了sleep方法,导致在Activity销毁时锁未被正确释放。

四、使用 LeakCanary 进行内存泄漏检测

LeakCanary是一个非常好用的内存泄漏检测库。使用LeakCanary可以方便地检测出应用程序中的内存泄漏。下面是一个简单的示例:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        LeakCanary.install(this);
    }
}

public class MyActivity extends Activity {
    private static List mLeakedList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (int i = 0; i < 10000; i++) {
            Object obj = new Object();
            mLeakedList.add(obj);
        }

        // Add this line to detect memory leaks
        LeakCanary.install(this.getApplication());
    }
}


在这个示例中,我们在Application的onCreate方法中初始化了LeakCanary,并在MyActivity的onCreate方法中添加了一些内存泄漏。当Activity销毁时,LeakCanary会检测出这些泄漏并发出警告。

顶部