【问题标题】:Using WeakReferences in Java在 Java 中使用弱引用
【发布时间】:2013-06-07 00:18:52
【问题描述】:

我一直在尝试在我的 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;
    }

【问题讨论】:

  • 请遵循 Java 命名约定。这是weakCampaingListcampaingList,而不是weak_campaing_listcampaingList。此外,您可能正在寻找的单词拼写为 campaign
  • @MrH:仍然不清楚你想在内存中保留哪些对象,以及在什么情况下它们可以被 GC 处理。没有这些信息,任何人都无能为力。
  • oohhh 好的,现在我和你在一起,我不需要保留活动列表。
  • 您是在尝试实现弱引用,还是尝试使用弱引用?如果 Dalvik VM 没有提供 WeakReference 类供您使用(我认为这不太可能),您将需要实现弱引用,这需要对特定垃圾收集器的深入了解和集成在系统上使用。
  • 是的,我正在尝试实现WeakReference。在我阅读的几乎所有文档中,我发现每个人都建议WeakReferencesSoftReferences 是用于内存管理的好方法。在我提出问题的链接中。现在我更困惑了。在Android开发中使用WeakReference好吗?当您提到“WeakReference 类”时,这就是您所指的:import java.lang.ref.WeakReference; 然后是的。

标签: java performance memory-management weak-references


【解决方案1】:

在 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);
    }
}

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

  1. 增加应用程序的内存需求
  2. 提高应用程序的 CPU 要求
  3. 当您仍需要使用的对象意外被垃圾回收时,引入难以重现的错误

原始帖子中的代码不包含确定您是否需要使用弱引用的信息或证据,也没有提供必要的信息来显示它们在解决特定问题时的正确用途 /em> 应用程序的约束。以上信息是对弱引用的一般评论,可以帮助您了解如何进行。

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

【讨论】:

  • @MrH 我根据这些信息更新了我的帖子(见最后一段)。
  • 酷。只是为了我的理解。如何有效地将campaignList放入WeakRefrence?
  • @MrH 你不能。您在上面发布的代码只会因使用弱引用而受到伤害。
  • 那么如何在使用大数组后保持内存干净呢?尤其是当应用需要一些额外的内存时。
  • 这就是垃圾收集器的工作。当您从getTheCampaign 返回时,campaignList 变量超出范围,垃圾收集器可以回收内存。
【解决方案2】:

试试这个

String[] campaing_list ....

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

【讨论】:

  • 谢谢伙计。您能否让我知道我所做的与您在性能方面建议的代码之间的区别。我也编辑了我的问题
  • 你将整个数组作为弱引用(1个对象)),正在做的是将整个数组对象设置为弱引用(数组对象)。
  • 很酷,那么 String[] campaingList 会发生什么......这会在内存中徘徊而不被释放吗?
  • 对不起,伙计,我很清楚你的方法在内存管理方面会更有效吗?看起来它在内存中创建了更多对象。 (抱歉我的问题,我需要在脑海中说清楚。我阅读了很多文件,但我还无法理解这个概念:(
【解决方案3】:

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

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

如果您无法重新加载列表中的单个条目,您可能希望对整个列表有一个 WeakReference。然后每当你需要访问它时,你需要查看它是否被 gc'ed,如果是则重新加载它。

你写道:

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

每当您检查引用上的 get() 是否为非空时,将结果保存在变量中并在之后使用它;不要做第二个 get() 假设引用仍然存在。每一次在一个蓝月亮,它都不会 - 垃圾收集器在此期间捡起它。如果您持有一个包含引用内容的变量,则不会发生这种情况。

在您真正确信自己理解它们之前,我不会在生产代码中使用 Wea​​kReferences。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多