Java: WeakReference.get() not returning null - java

I'm new to WeakReferences, so I'm just trying to understand this. I threw together this short snippet of code to test their behavior. I plan to use them in a project I'm working on, because I need to track references to objects on a temporary basis. ie, I want to have a reference to them in a collection so long as they're not being used anywhere else.
So far, though, this short test code sample hasn't been working like I want it to. No matter how long I wait, weakRef.get() always returns the value, it never returns null.
Please help me figure out what I'm doing wrong. Thanks.
public static void main(String[] args) throws Exception{
String s = "Hello World!";
WeakReference<String> weakRef = new WeakReference<>(s);
System.out.println("Original1: " + s);
System.out.println("Weak1: " + weakRef.get());
s = null;
Thread.sleep(10000);
Runtime.getRuntime().gc();
int count = 0;
while(weakRef.get() != null){
System.out.println("Not null " + count);
count++;
Thread.sleep(1000);
}
System.out.println("Null");
}
Edit: Updated my code sample. I even tried manually invoking the garbage collector, and the the final println still outputs "Weak2: Hello World!".
Edit 2: Changed it again. Moved the 10 second wait to before the garbage collection, then included the loop. The loop keeps running so far for 48 seconds (before I decided to close it) after the garbage collection.

In Java, string literals, like your "Hello, World!" are "interned"; that is, they are put in a cache for reuse. As long as a loaded class depends on one of these interned strings, it won't be reclaimed by the garbage collector, and that is what's preventing your WeakReference from being cleared. Try this instead:
WeakReference<String> weakRef = new WeakReference<>(new String(s));
Of course, a string that isn't assigned from a literal value in your source code—for example, a String created from file contents—will be garbage collected at an appropriate time. You just picked a subtly tricky example to test.

Related

Deallocating memory allocated to objects in Java

In C++ you can deallocate the memory allocated to an object like this:
int main(){
string myString("MyString");
string *stringPointer = &myString;
cout<<myString<<" "<<*stringPointer;
delete stringPointer;
cout<<myString; //crash
return 0;
}
In binary search trees (or any other case), when you need to delete a node, you make it eligible for garbage collection in Java. But you can't do it like this
Node nodeToDelete = getNodeToDelete();
nodeToDelete = null; //the original reference is still there in the tree
This is like setting a pointer variable to NULL in C++
pointerVariable = NULL;
For the BST delete function to work in Java, we need to go the parent of the node and set the child node to delete to null.
Is there a Java language feature like delete in C++ to make things easier?
No, there is no language feature in Java that allows you to selectively delete a specific object ahead of time (like del in Python). You'll need to trust that the garbage collector will do its job. (And usually, it does so very well.)
Java's garbage collector is based on object reachability (not on reference counting like in CPython, not on memory scanning like in Boehm GC). This mans that any object for which there is no live reference is subject to garbage collection. The reference can be indirect but references from dead objects and dead cycles will not irritate the garage collector.
Some examples:
class Dummy {
String name;
Dummy other;
Dummy(String name) { this.name = name; }
}
void f1() {
Dummy peter = new Dummy("Peter");
peter.other = new Dummy("Fred");
peter.other.other = new Dummy("Megan");
// None of the objects is eligible for garbage collection since
// "Peter" is live and "Fred" can be reached via "Peter" (therefore
// "Fred" is alive) and "Megan" can be reached via "Fred".
peter.other = null;
// Now the reference to "Fred" is lost which makes him a candidate
// for garbage collection. "Megan" is dead too because the
// reference from the dead object "Fred" does not count.
// As the method returns, all three objects are dead and can be
// collected.
}
void f2() {
Dummy clementine = new Dummy("Clementine");
clementine.other = new Dummy("Charles");
clementine.other.other = new Dummy("Caroline");
clementine.other.other.other = clementine;
// Here we have a cycle of
//
// +--> "Clementine" --> "Charles" --> "Caroline" --+
// | |
// +------------------------------------------------+
//
// and since "Clementine" is live, all three are.
clementine = null;
// Once we loose the reference to "Clementine", the cycle still
// exists (every object is referenced by at least one other object)
// but the cycle is dead. Hence, all three are subject to garbage
// collection.
}
The key to using the Java garbage collection effectively is to not keep any references to objects around that you don't need any more. In your binary tree, doing
this.leftChild = null;
will make the entire left sub-tree eligible for garbage collection. (That is, if nobody else is keeping a live reference to one of the nodes.)
Only very rarely you'll want to allow the garbage collector to collect a live object. This can be done using java.lang.ref.SoftReference. The only times I found them useful is for a cache.
import java.lang.ref.SoftReference;
class StoryOfMyLife {
private final String story;
private transient SoftReference<String[]> cachedWords;
public StoryOfMyLife(final String story) {
this.story = story;
this.cachedWords = new SoftReference<String[]>(null);
}
public synchronized String getWordN(final int n) {
String[] words = this.cachedWords.get();
if (words == null) {
// Called for the first time or cache was garbage collected.
words = this.story.split("\\s+");
this.cachedWords = new SoftReference<String[]>(words);
}
// Note that we are keeping the cache live for the duration of
// this method by keeping the reference 'words'. Once this
// method returns, the cache becomes subject to garbage
// collection again.
return words[n];
}
}
In this example, the (potentially very expensive) splitting of the long string into words is only done lazily and the result is cached. However, if the system runs low on memory, we allow the cache to be garbage collected since we can re-compute it at any time.
You can read more about the garbage collector built into Oracle's HotSpot JVM at Oracle's website.
Java manages memory with reachability-based garbage-collection, thus in order to free memory, just make sure it's no longer reachable.
Few Java-objects need to be cleaned up timely:
Namely those which manage native resources. Use dispose() on them, or if block-scoped, try using.
Side-note: C++ is allergic to freeing memory with the wrong method:
Use scope-exit for automatic-storage (that's what you used). This is the basis for RAII.
use delete to complement new.
use delete [] to complement new[].
use free to complement malloc, calloc and realloc.

Should I cache System.getProperty("line.separator")?

Consider such method:
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
for (final Room room : map)
{
sb.append(room.toString());
sb.append(System.getProperty("line.separator")); // THIS IS IMPORTANT
}
return sb.toString();
}
System.getProperty("line.separator") can be called many times.
Should I cache this value with public final static String lineSeperator = System.getProperty("line.separator")
and later use only lineSeperator?
Or System.getProperty("line.separator") is as fast as using a static field?
I see your question as presenting a false dichotomy. I would neither call getProperty every time, nor declare a static field for it. I'd simply extract it to a local variable in toString.
#Override
public String toString()
{
final StringBuilder sb = new StringBuilder();
final String newline = System.getProperty("line.separator");
for (final Room room : map) sb.append(room.toString()).append(newline);
return sb.toString();
}
BTW I have benchmarked the call. The code:
public class GetProperty
{
static char[] ary = new char[1];
#GenerateMicroBenchmark public void everyTime() {
for (int i = 0; i < 100_000; i++) ary[0] = System.getProperty("line.separator").charAt(0);
}
#GenerateMicroBenchmark public void cache() {
final char c = System.getProperty("line.separator").charAt(0);
for (int i = 0; i < 100_000; i++) ary[0] = (char)(c | ary[0]);
}
}
The results:
Benchmark Mode Thr Cnt Sec Mean Mean error Units
GetProperty.cache thrpt 1 3 5 10.318 0.223 ops/msec
GetProperty.everyTime thrpt 1 3 5 0.055 0.000 ops/msec
The cached approach is more than two orders of magnitude faster.
Do note that the overall impact of getProperty call against all that string building is very, very unlikely to be noticeable.
You do not need to fear that the line separator will change while your code is running, so I see no reason against caching it.
Caching a value is certainly faster than executing a call over and over, but the difference will probably be negligible.
If you have become aware of a performance problem that you know relates to this, yes.
If you haven't, then no, the lookup is unlikely to have enough overhead to matter.
This would fall under either or both of the general categories "micro-optimization" and "premature optimization." :-)
But if you're worried about efficiency, you probably have a much bigger opportunity in that your toString method is regenerating the string every time. If toString will be called a lot, rather than caching the line terminator, cache the generated string, and clear that whenever your map of rooms changes. E.g.:
#Override
public String toString()
{
if (cachedString == null)
{
final StringBuilder sb = new StringBuilder();
final String ls = System.getProperty("line.separator");
for (final Room room : map)
{
sb.append(room.toString());
sb.append(ls);
}
cachedString = sb.toString();
}
return cachedString;
}
...and when your map changes, do
cachedString = null;
That's a lot more bang for the buck (the buck being the overhead of an extra field). Granted it's per-instance rather than per-class, so (reference earlier comment about efficiency) only do it if you have a good reason to.
Since it's so easy to do, why not? At the very least the implementation of System.getProperty() will have to do a hash table lookup (even if cached internally) to find the property you are requesting, then the virtual method getString() will be called on the resulting Object. None of these are very expensive but will need to be called multiple times. Not to mention many String temporaries will be created and need GCing after.
If you move this out to the top of your loop and reuse the same value, you avoid all of these problems. So why not?
If the system property is guaranteed to remain constant during the application it can be cached but in general you will loose the feature of the property which is changing the behavior when you change it.
For instance a text generator could use the property to generate text for windows or for linux and allow the property to be changed dynamically in the application, why not ?
In general, catching a property implies making useless the function setProperty.

Null pointer exception in server

This is a client-server programm.
For each client server has a method, which checks if there are some messages to this client.
Code:
while (bool) {
for(int j = 0;j<Start.bases.size();j++){
if(Start.bases.get(j).getId() == id){
if(!Start.bases.get(j).ifEmpty()){
String output = Start.bases.get(j).getMessage();
os.println(output);
System.out.println(output +" *FOT* "+ addr.getHostName());
}
}
}
Each thread has an id.
So everything seems to be OK, but I get strange null pointer Exception at this line
if(Start.bases.get(j).getId() == id){
id - integer.
It is really strange, because I have run in debug this part and checked that "bases" and "id" are not null and bases have apropriate fields.
bases is not empty.
By the way bases is static(because every thread can use it) and bases is declared before this method is used.
This line doesn't cause problems
for(int j = 0;j<Start.bases.size();j++){
May it is because of method getId() ?
public int getId(){
return id;
}
What is the problem?
Edited.
static ArrayList<Base> bases;
bases = new ArrayList<Base>();
Class Base:
public class Base {
private ServerThread st;
private int id;
private String name;
private ArrayList<String> messages;
public Base(String n, ServerThread s_t, int i_d){
messages = new ArrayList<String>();
st = s_t;
name = n;
id = i_d;
}
public String getName(){
return name;
}
public int getId(){
return id;
}
public ServerThread getThr(){
return st;
}
public String getMessage(){
String ret = "";
if(!messages.isEmpty()){
ret = messages.get(0);
messages.remove(messages.get(0));
}
return ret;
}
public void addMessage(String m){
messages.add(m);
}
public boolean ifEmpty(){
return messages.isEmpty();
}
}
Thanks.
In this line of code:
(Start.bases.get(j).getId() == id
you may have such exception in such cases:
1) bases is null - you said its wrong
2) bases.get(j) - it may occur only if you collection size was reduced during iteration(as mentioned Gray)
3) Start.bases.get(j).getId() is null. But as you mentioned getId() method return primitive int, so its not the case as in this situation you receive null ponter while casting - in line " return id;".
So you should check second case.
Given this:
"I have run in debug this part and checked that "bases" and "id" are not null and bases have apropriate fields"
and this:
bases is static(because every thread can use it)
I think it's pretty likely that you have a race condition. In a race condition, there are two threads simultaneously accessing the same data structure (in this case, Start.bases). Most of the time, one thread's code completes faster, and everything goes the way you expect them to, but occasionally the other thread gets a head-start or goes a little faster than usual and things go "boom".
When you introduce a debugger with a break point, you pretty much guarantee that the code with the break point will execute last, because you've stopped it mid-execution while all your other threads are still going.
I'd suggest that the size of your list is probably changing as you execute. When a user leaves, is their entry removed from the "base" list? Is there some other circumstance where the list can be changed from another thread during execution?
The first thing I'll suggest is that you switch your code to use iterators rather than straight "for" loops. It won't make the problem go away (it might actually make it more visible), but it will make what's happening a lot clearer. You'll get a ConcurrentModificationException at the point where the modification happens, rather than the less helpful NullPointerException only when a certain combination of changes happens.):
for(Base currentBase : Start.bases)
{
if(currentBase.getId() == id && !currentBase.ifEmpty())
{
String output = currentBase.getMessage();
os.println(output);
System.out.println(output +" *FOT* "+ addr.getHostName());
}
}
If you do get a concurrent modification exception with the above code, then you're definitely dealing with a race condition. That means that you'll have to synchronize your code.
There are a couple of ways to do this, depending on how your application is structured.
Assuming that the race is only between this bit of code and one other (the part doing the removing-from-the-list), you can probably solve this scenario by wrapping both chunks of code in
synchronized(Start.bases)
{
[your for-loop/item removal code goes here]
}
This will acquire a lock on the list itself, so that those two pieces of code will not attempt to update the same list at the same time in different threads. (Note that it won't stop concurrent modification to the Base objects themselves, but I doubt that's the problem in this case).
All of that said, any time you have a variable which is read/write accessed by multiple threads it really should be synchronized. That's a fairly complicated job. It's better to keep the synchronization inside the object you're managing if you can. That way you can see all the synchronization code in one place, making you less likely to accidentally create deadlocks. (In your code above, you'd need to make the "for" loop a method inside your Start class, along with anything else which uses that list, then make "bases" private so that the rest of the application must use those methods).
Without seeing all the other places in your code where this list is accessed, I can't say exactly what changes you should make, but hopefully that's enough to get you started. Remember that multi-threading in Java requires a very delicate hand!

How does recursion work here?

Recursion is a new practice for me and I am trying to get better at it and understand how the methods return. I have the following program but am unfailiar with how to use the this keyword. Can you please review the code and walk me through the program showing the values held by the variables as the methods execute?
I have tried numerous things to determine how the value answer in the compute method holds 14 after execution can anyone walk me through the first few recursive calls so I can try and figure out the rest?
public class Recurs1 {
public static void main (String [] arg) {
Recurs1 r = new Recurs1();
r.compute();
}
public void compute() {
int [] stuff = {1, 2, 3, 4};
int answer = this.go(stuff, 0);
System.out.println("The answer is " + answer);
}
private int go(int[] numbers, int spot) {
if (numbers.length == spot) return spot;
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
}
Ok so a few things I notice here:
The purpose of go() seems to be calculating the sum of the numbers in the array. If this is the case, your method should look like this:
private int go(int[] numbers, int spot) {
if (numbers.length - 1 == spot) return numbers[spot];
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
This is because numbers.length in this case will return 4, but the last element in this array is at index 3 (arrays are 0-indexed).
This way, when the function is called with the second parameter set to 3, it will return the value of the last element in the array and then the code will "bubble up" (as I like to call it) and calculate the sum of the elements by subsequently returning the current summed value + the value of the current call.
As for your problem with the this keyword, it's actually very simple. this always refers to the current class instance your code is in. In this case, you create a Recurs1 instance called r in your main function so whenever you call a method on that particular object, the this keyword used in those methods will refer to r. If you created multiple Recurs1 objects (each with potential different internal states) in your program, their respective this references would always point to themselves allowing you to access their member variables and methods.
Hope that helps and good luck, recursion is usually what most people have trouble getting their heads around at first but once you get used to it it's pretty cool!
OK so this is not an answer to your question per se, more like a lesson in recursion.
Keep in mind I have never tried to to do this with a java class.
Recursion means a function that calls itself repeatedly until a answer has been reached, or your function detects you are running out of stack space.
You first step into the function determines if you will call yourself.
When you call yourself you will push a new copy of the data onto the stack and begin executing. I think in the case of java you will allocate a new object into the heap ( don't quote me on this ) and each invocation will have a new set of variables that get populated with new values.
As you recurse deeper and deeper you simply allocate new copies of the object until you find the answer or run out of memory.
If you find the answer you then return the result to the previous level in the stack of objects eg:
int foo(int i ){
if(some condition){
return foo(i);
} else
return i
}
as You can see if the condition tests true the foo() keeps getting called. Now at each call, the variables of foo() are saved for as many levels deep as you go. If the condition tests false then each instance of foo() returns to the previous until you are at the original invocation of foo() which then returns to the caller of foo().
Clear as Mud?

ArrayList creation: (some object) cannot be stored in an array of type java.lang.Object[]

Usually, the code block works perfect. On very rare occasions though, the "new ArrayList" throws an Exeption my.namespace.CacheEntry cannot be stored in an array of type java.lang.Object[].
Checking Google, someone else seemed to get this exception on an Acer A500 with 3.1 (which is the device I got it, too). I don't see any hit for this in generic Java or whatever, so may be some very very Honeycomb special case or even a VM bug?
private long expireCache(HashMap<String, CacheEntry> map) {
long count = 0;
// next line will sometimes throw the exception:
ArrayList<CacheEntry> entries = new ArrayList<CacheEntry>(map.values());
Collections.sort(entries);
The CacheEntry class is quite regular, too:
final class CacheEntry implements Comparable<CacheEntry> {
public File file;
public Long time;
CacheEntry(File cacheFile) {
// retreive the lastModified only once, don't do heavy I/O for sorting,
// keep it desynced from filesystem so nothing bad happens when the
// file gets changed while sorting:
file = cacheFile;
time = cacheFile.lastModified();
}
// "touch" the cached last modified time
public void touch() {
time = System.currentTimeMillis();
}
// return the long comparable of last modified time
public int compareTo(CacheEntry c) {
return time.compareTo(c.time);
}
}
I don't see anything wrong with this code. Anyone?
may be some very very Honeycomb special case or even a VM bug?
Yes, looks like it, because according to Java semantics, there isn't anything that "cannot be stored in an array of type java.lang.Object[]" - except primitives, but those can't be values in a HashMap

Categories

Resources