Mr H
Mr H

Reputation: 5304

Using WeakReferences in Java

I have been trying to use WeakReference in my Android projects and I have never had any success. Now I really need it as I am dealing with old devices and I have to keep the memory clean as much as I can.

Anyway, I have an array which has about 1000 list of different strings in it. I need to load it then find a string in it.

This is how I am currently using it:

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

Is this the correct way of using WeakReference? If yes then what I don't understand is the array is getting hydrated at String[] and then I pass it to the WeakReference. So doesn't this mean I have 2 spots on the memory allocated to one array? Or I am completely misunderstanding the WeakReference concept?

A very good resource that I found among all the resources is this one:

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

Edit:

My code works with no issue. Just need to know if I am doing it correct in terms of performance.

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

My Entire Method

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

Upvotes: 0

Views: 6485

Answers (3)

Ed Staub
Ed Staub

Reputation: 15690

You need to think about this in terms of your requirements for correct behavior. In particular, if an individual string is garbage-collected, and you try to find it, what's going to happen?

If you're going to use this, you need to test it by stress-testing - making sure that weak references are being garbage-collected. You don't really know whether it's working correctly until you do so.

If you have no way to reload individual entries in the list, you probably want to have a single WeakReference to the entire list. Then whenever you need to access it, you need to see whether it's been gc'ed, and reload it if so.

You wrote:

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

Whenever you check the get() on a reference is non-null, save the result in a variable and use it after that; don't do a second get() assuming the reference will still be there. Every once in a blue moon, it won't be - the garbage collector picked it up in the meantime. If you're holding a variable with the reference contents in it, that can't happen.

I wouldn't use WeakReferences in production code until you're really confident you understand them.

Upvotes: 0

Sam Harwell
Sam Harwell

Reputation: 99869

In garbage collected languages such as Java, weak references are often used to prevent static or long-lived objects from causing memory to never be released. For example, suppose your application contained a singleton class ClipboardMonitor that kept track of the last document where the user pressed 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;
    }
}

In this implementation, if the user presses Ctrl+C and then closed the document window (but not the application), the lastDocument field would keep holding a reference to the document and the garbage collector could not reclaim that memory. Weak references can resolve that problem.

In the following modified code, the static field lastDocument is turned into a weak reference, so even if the user presses Ctrl+C and a document is assigned to this field the garbage collector can reclaim the document memory after the document is closed.

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

This example highlights the most important point about weak references: weak references do not save memory all by themselves. Rather, they are used to resolve a particular type of problem that can cause apparent memory leaks in an application written in a garbage collected language. If your application design does not require the use of weak references to address particular design limitations, then adding weak references will only have one (or more) of the following consequences:

  1. Increase the memory requirements of your application
  2. Increase the CPU requirements of your application
  3. Introduce difficult to reproduce bugs when objects you still need to use get unexpectedly garbage collected

The code in the original post does not contain information or evidence to determine whether or not you need to use weak references, nor does it provide the information necessary to show their correct use in addressing a particular constraint of your application. The information above is general commentary on weak references that may help you understand how to proceed.

Edit: Based on the updated method you posted, it appears that weak references are not necessary in your case. They are not providing any benefits, and are causing at least problems 1 and 2 from the list above. Depending on the particular garbage collector implementation, they may result in problem 3 as well (throwing a NullPointerException when you try to call contains).

Upvotes: 5

Mohammad Ersan
Mohammad Ersan

Reputation: 12444

try this

String[] campaing_list ....

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

Upvotes: 0

Related Questions