在Java中使用WeakReferences

时间:2013-06-07 00:18:52

标签: java performance memory-management weak-references

我一直在尝试在我的Android项目中使用WeakReference,但我从来没有取得任何成功。现在我真的需要它,因为我正在处理旧设备,我必须尽可能地保持内存清洁。

无论如何,我有一个数组,其中包含大约1000个不同字符串列表。我需要加载它然后在其中找到一个字符串。

这就是我目前使用它的方式:

String[] campaignList = context.getResources().getStringArray(R.array.campaignList);
WeakReference<String[]> weakCampaignList = new WeakReference<String[]>(campaignList);

这是使用WeakReference的正确方法吗? 如果是,那么我不明白的是阵列在String[]得到水合,然后我将它传递给WeakReference。那么这是不是意味着我在分配给一个阵列的内存上有2个点?或者我完全误解了WeakReference概念?

我在所有资源中发现的一个非常好的资源就是这个:

http://neverfear.org/blog/view/150/Strong_Soft_Weak_and_Phantom_References_Java

编辑:

我的代码没有问题。只需要知道我的表现是否正确。

for (int i = 0; i < weakCampaignList.get().length; i++) {
  Log.d(TAG,"weakCampaignList: "+weakCampaignList.get()[i]);
}

我的整个方法

public static String getTheCampaign(String country, Context context) {
        String campaign = "";
        campaign = "annual_subscription_" + country;

        String[] campaignList = context.getResources().getStringArray(
                R.array.campaign_list);

        ArrayList<WeakReference<String>> weakCampaignList = new ArrayList<WeakReference<String>>();
        for (String s : campaignList) {
            weakCampaignList.add(new WeakReference<String>(s));
        }

        if (country.equals("") || country.isEmpty()) {
            campaign = "annual_subscription_us";
        } else {
            for (int i = 0; i < weakCampaignList.size(); i++) {
                if (weakCampaignList.get(i).get().contains(campaign)) {
                    campaign = weakCampaignList.get(i).get();
                    return campaign;
                } 
            }
        }
        return campaign;
    }

3 个答案:

答案 0 :(得分:5)

在Java等垃圾收集语言中,弱引用通常用于防止静态或长期存在的对象导致永远不会释放内存。例如,假设您的应用程序包含单个类ClipboardMonitor,它跟踪用户按下的最后一个文档 Ctrl + C

class ClipboardMonitor {
    static Document lastDocument;

    // return the last document where Ctrl+C was pressed
    static Document getLastDocument() {
        return lastDocument;
    }

    static void copyCommand(Document document) {
        lastDocument = document;
    }
}

在此实现中,如果用户按 Ctrl + C 然后关闭文档窗口(但不关闭应用程序),lastDocument字段将保持不变持有对文档的引用,垃圾收集器无法回收该内存。弱引用可以解决这个问题。

在以下修改后的代码中,静态字段lastDocument变为弱引用,因此即使用户按下 Ctrl + C 和文档分配给此字段后,垃圾收集器可以在文档关闭后回收文档内存。

class ClipboardMonitor {
    static WeakReference<Document> lastDocument;

    // return the last document where Ctrl+C was pressed, or null if
    // that document was closed and the garbage collector has already
    // reclaimed the memory
    static Document getLastDocument() {
        WeakReference<Document> weakDocument = lastDocument;
        return weakDocument != null ? weakDocument.get() : null;
    }

    static void copyCommand(Document document) {
        lastDocument = new WeakReference<Document>(document);
    }
}

这个例子强调了关于弱引用的最重要的一点:弱引用本身并不能节省内存。相反,它们用于解决在以垃圾收集语言编写的应用程序中可能导致明显内存泄漏的特定类型的问题。如果您的应用程序设计要求使用弱引用来解决特定设计限制,那么添加弱引用只会产生以下一种(或多种)后果:< / p>

  1. 增加应用程序的内存要求
  2. 增加应用程序的CPU要求
  3. 当您仍然需要使用的对象意外地收集垃圾时,引入难以重现的错误
  4. 原始帖子中的代码不包含确定您是否需要使用弱引用的信息或证据,也不提供显示其正确用于解决特定<的必要信息/ em>您的应用程序的约束。以上信息是关于弱参考的一般评论,可能有助于您了解如何继续。

    编辑:根据您发布的更新方法,您的案例中似乎不需要弱引用。它们没有提供任何好处,并且正在导致上面列表中的至少问题1和2。根据特定的垃圾收集器实现,它们也可能导致问题3(当您尝试调用NullPointerException时抛出contains)。

答案 1 :(得分:0)

试试这个

String[] campaing_list ....

        ArrayList<WeakReference<String>> list = new ArrayList<WeakReference<String>>();
        for (String s : campaing_list) {
            list.add(new WeakReference<String>(s));
        }

答案 2 :(得分:0)

您需要根据对正确行为的要求来考虑这一点。特别是,如果单个字符串被垃圾收集,并且您试图找到它,会发生什么?

如果你打算使用它,你需要通过压力测试来测试它 - 确保弱引用被垃圾收集。在你这样做之前,你真的不知道它是否正常工作。

如果您无法在列表中重新加载单个条目,则可能希望对整个列表具有单个WeakReference。然后,无论何时需要访问它,您都需要查看它是否已被gc,并重新加载,如果是这样的话。

您写道:

if (weakCampaignList.get(i).get().contains(campaign)) {
                campaign = weakCampaignList.get(i).get();

每当检查引用的get()是非null时,将结果保存在变量中并在之后使用它;不要做第二次get()假设引用仍然存在。每一次在蓝色的月亮中,它都不会 - 垃圾收集者在此期间捡起它。如果你持有一个带有参考内容的变量,那就不会发生。

我不会在生产代码中使用WeakReferences,除非你真的有信心理解它们。