Darth Coder
Darth Coder

Reputation: 1798

Memory management for Immutable Objects

I have a conceptual doubt regarding the memory management of Immutable objects such as String Objects in java and other languages. For example, if I have a String object "str" holding the value "Hello" and I do the following:

String str = "Hello";
str = str.concatenate("World");

In this case, as I understand it a new String object with the state "Hello World" is created and referenced back to str. Now, in Java (and in most other object oriented languages as well) the lifetime of any object is as long as its reference is alive. So where does the object holding "Hello" go. Does it reside in the memory heap until a garbage collector takes care of it at its own leisure? Also, what about languages that do not support a garbage collector and have to depend on class destructors?

Also, if mutable objects such as StringBuffer and StringBuilder are much more flexible and performance friendly, why make objects immutable in the first place, while designing the language?? (I mean why aren't String Objects mutable right from the beginning instead of having to introduce new structures such as String Buffers in subsequent JDK releases?).

It would be great if someone can guide me on this. I am new to this so a clear, fundamental explanation would be highly appreciated. Thanks.

Upvotes: 4

Views: 5575

Answers (4)

anshulkatta
anshulkatta

Reputation: 2064

So where does the object holding "Hello" go

The Reference to "Hello" , str ,is assigned new value , so the reference to value "Hello" is lost , but its still in the pool , available , Garbage collector may collect it and remove it from heap , it is not known exactly , let say in the future code you still use "Hello" string

String againhello= "Hello" ;

Then in this case , Garbage collector should not collect it because , "Hello" string is created and still again used , only the new reference has been assigned.

The concept behind the mutability and Immutability of object is , any two object if having same value , should have same hashcode and should return true for equals method , this hold true for String objects , but to increase performance

they set String as immutable because , they dont want the heap to be filled with same value and number of different objects , for instance , let say

String sre="Hello";

String str="Hello"; 

If there were no immutability of String , then there will be two objects in heap , but there is only one object , only two reference variables here.

what is difference between String and StringBuilder class. 

StringBuilder class has been added in Java 5 and provided similar functionality of StringBuffer (ie.. mutable string ) where on every modification on string , no new object gets created now benefit of using StringBuilder is that its comparatively faster than StringBuffer because StringBuffer is a synchronized class while StringBuilder is not , so in case if you want to use StringBuffer in a environment where thread safety is not concern , consider using StringBuilder for better performance.

By default, all Java classes are mutable i.e contents of their instances can be modified. But there are few advantages that immutability offers (http://download.oracle.com/javase/tutorial/essential/concurrency/immutable.html), and that's why some classes are made immutable by marking them as final. The classes in question are String and Wrapper classes, and if you think logically about them (any immutable class), then the description in the link provided would start making sense. Let us address each of the two separately:

String class: 

As mentioned in SCJP page 433 by Kathy Siera and Bert Bates, as applications grow, its very common to have a lot of redundancy in the String literals for a program. Hence, in order to address this issue, the designers of Java came up with the concept of String pool which improves performance by making efficient use of available memory. But now, as you might imagine, if several reference variables refer to the same String without even knowing it, it would be bad if any of them could change the String's value. Hence, there arose the need of making this String class immutable.

Wrapper classes:

One of the objectives of making wrapper classes is to provide a mechanism to treat primitives with activities reserved for objects, like being added to Collections, or returned from a method with an object return value. If you think about a collection, it would often be the case that it is accessed by multiple threads. If the wrapper classes weren't mutable, it would run into the risk of concurrent modification and thus lead to inconsistent states. Thus, in order to avoid conflicts, wrapper classes are made immutable.

So, in general, whenever you come across an immutable class, it would be logical to think of its instances being used in a concurrent manner. Also, if you do not want your object contents to be modified (one of the reasons being concurrent access), then make the class immutable.

Upvotes: 2

Patashu
Patashu

Reputation: 21793

Strings are immutable to follow the principle of Least Surprise.

Primitive types such as int, float and char are copied by value - if you copy its value to another place and edit one of the copies, it is actually an entirely new primitive that has been edited, and no changes are seen in the other place.

Strings are not primitives, but they are 'treated as primitives' in a lot of ways, conceptually. Since we are so used to the copy by value traits of primitives, what happens if Strings were made to be mutable but we forgot and treated them as though they had copy-by-value semantics?

Things could get messy. For instance:

-Any time you returned a string, you would have to return a copy of the string, or else the consumer of the string could edit it, and suddenly your string is edited too! For example, data like usernames, passwords, messages could get 'surprisingly' edited.

-Security is an issue. If you call unknown code and it alters a string you are using, then you have to remember and make copies of all the strings (performance issues also!) or suffer random detrimental behaviour when they change out from under your feet.

-String interning would be impossible (which is a mechanic by which strings with the same value can be handed out reusably, so only one object of that string value exists instead of two). The string intern table relies on strings being immutable.

It is a tradeoff - performance in some ways, vs performance in other ways (now needing to copy strings whenever you want to be sure the thing you pass the string to does not edit it is a performance loss!), more difficulty reasoning about your code (strings are so ubiquitous, and if any string could change at any time for any reason, if it's EVER been exposed and another reference acquired to it...), etc.

Upvotes: 2

selig
selig

Reputation: 4844

This is actually a question about the java String class in particular - not immutability in general. When Java was first introduced the designers decided to make String special - in some ways it's halfway between a reference type and a primitive type.

The advantage we get with String is that a common pool of string literals is kept by the virtual machine stopping the Heap getting filled up - see here for a description. The reasoning behind this is that much of the memory of a program can be taken up with storing commonly used strings. See also String.intern.

For any other kind of immutable object this isn't the case (sadly). Your question about where str goes has been answered by somebody else - it follows the normal garbage collection rules that I'm sure you know about (or can find out).

Perhaps the most interesting part of your question is

Also, if mutable objects such as StringBuffer/StringBuilder are much more flexible and performance friendly, why make objects mutable in the first place, while designing the language?? (I mean why aren't String Objects mutable right from the beginning instead of having to introduce new structures such as String Buffers in subsequent jdk releases?).

My answer would be that the common case is that we have lots of identical strings, and we want to optimise for the common case. Note also that the Java compiler uses StringBuilder when concatenating strings. For example take this code

public class StringBuilderTest {

  public static void main(String [] args){

    String hello = "hello ";
    String world = "world";
    System.out.println(hello+world);
   }
}

and disassemble it using

javap -c StringBuilderTest

and get the following bytecode for the main method

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String hello 
       2: astore_1      
       3: ldc           #3                  // String world
       5: astore_2      
       6: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       9: new           #5                  // class java/lang/StringBuilder
      12: dup           
      13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      16: aload_1       
      17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: aload_2       
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      27: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      30: return        
}

which uses a StringBuilder to perform the append.

Upvotes: 4

Jens Birger Hahn
Jens Birger Hahn

Reputation: 917

Your probably on the outer rim territories, Darth Coder and Google is not available, so here's an entry level explanation of Reference Objects and Garbage collection.

A technical explanation of how this exactly works in the Oracle Java VM is here.

The key idea to understand garbage collection in any language is that of reachability. Every object needs to be reachable by a path from a root reference. What are root references? Examples are the chain of method invocation stack frames, Classes, Threads, JNI references and a few more. Everything which is not reachable from these roots is considered not used and its space is reclaimed with methods described in the articles. Garbage collection is by no means trivial and a vivid research area, so be patient :-).

Upvotes: 0

Related Questions