0

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;
    }
Mr H
  • 5,254
  • 3
  • 38
  • 43
  • Please follow Java naming conventions. It's `weakCampaingList` and `campaingList`, not `weak_campaing_list` and `campaingList`. Also, the word you're probably looking for is spelled *campaign*. – wchargin Jun 07 '13 at 00:43
  • @MrH: It's _still_ not clear what objects you want to keep in memory and under what circumstances it's okay for them to get GC'd. Without that information, there's little anyone can do to help. – Louis Wasserman Jun 07 '13 at 01:31
  • oohhh ok now I am with you, I dont need to keep the campaignList. – Mr H Jun 07 '13 at 01:34
  • Are you trying to *implement* weak references, or are you trying to *use* weak references? You would need to *implement* weak references if the Dalvik VM did not provide a `WeakReference` class for you to use (which I find unlikely), which requires intimate knowledge of and integration with the particular garbage collector in use on the system. – Sam Harwell Jun 07 '13 at 01:44
  • Yes I am trying to implement the `WeakReference`. In almost any document I read, I found that everyone suggesting `WeakReferences` or `SoftReferences` are good way to use for the memory management. In the link that I put in the question. Now I am more confused. Is is good to use `WeakReference` in Android development? Is this what you are referring to when you mention "WeakReference class": `import java.lang.ref.WeakReference;` then yes. – Mr H Jun 07 '13 at 01:50
  • I think you have your terminology mixed up. Android provides a [`WeakReference`](http://developer.android.com/reference/java/lang/ref/WeakReference.html) implementation, so you do not need to implement your own. You can simply use the one that is already provided. – Sam Harwell Jun 07 '13 at 01:52
  • so based on what you are referring, Am I implementing it correctly? Or again I am off the subject. – Mr H Jun 07 '13 at 01:57
  • for a complete example, see: http://www.javacodegeeks.com/2014/03/difference-between-weakreference-vs-softreference-vs-phantomreference-vs-strong-reference-in-java.html – Someone Somewhere May 13 '15 at 20:21

3 Answers3

5

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).

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • @MrH I updated my post based on that information (see the last paragraph). – Sam Harwell Jun 07 '13 at 02:42
  • Cool . just for my understanding. How can I put the campaignList in WeakRefrence efficiently? – Mr H Jun 07 '13 at 02:51
  • @MrH You can't. The code you posted above is only hurt by using weak references. – Sam Harwell Jun 07 '13 at 13:02
  • So how does one keep the memory clean after using a big array? Especially when app needs some extra memory. – Mr H Jun 08 '13 at 14:10
  • That's the job of the garbage collector. When you return from `getTheCampaign`, the `campaignList` variable goes out of scope and the garbage collector can reclaim the memory. – Sam Harwell Jun 08 '13 at 16:12
  • hmmm, fair enough. So how do I recognise places that I need to use `WeakReference`? Also what do you mean by long live object. I thought when I make an object, when there will be no reference to it, in the next cycle GC will collect it. I have a phobia that if I use `new` and make an object I will end up with that object not being collected by GC. Thanks for your answer too – Mr H Jun 09 '13 at 01:02
0

try this

String[] campaing_list ....

        ArrayList<WeakReference<String>> list = new ArrayList<WeakReference<String>>();
        for (String s : campaing_list) {
            list.add(new WeakReference<String>(s));
        }
Mohammad Ersan
  • 12,304
  • 8
  • 54
  • 77
  • Thanks mate. Can you please let me know the difference between what I have done and the code you are suggesting in terms of performance. I have edit my question too – Mr H Jun 07 '13 at 00:50
  • you doing the whole array as weak reference (1 object)), what am doing is set the whole array object as weak reference (array objects). – Mohammad Ersan Jun 07 '13 at 00:54
  • Cool, so then what will happen with the String[] campaingList .... will this going to hang around in the memory without getting released? – Mr H Jun 07 '13 at 00:57
  • Sorry mate just so I am clear will your method is more efficient in terms of memory management? It looks that it creates more objects in the memory. (Sorry for my questions I need to make it clear in my head. I read so many documents and I couldn't get the concept yet :( – Mr H Jun 07 '13 at 01:23
0

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.

Ed Staub
  • 15,480
  • 3
  • 61
  • 91