1

Reading the source code for String#substring (Java 1.7) it looks like it reuses the character array, but with different offset and length. This means that if I have an giant String that I substring, the initial string will never be reclaimed by GC (right?).

What's the easiest way to sure that the giant String is reclaimed? I am running JavaSE-1.7.

(For the curious, I'll be writing a radix implementation in Java to reduce memory usage. The answer to this question is essential to avoid the radix tree using more memory than necessary)

6
  • stackoverflow.com/questions/20081659/java-substring-memory-leak/… look at the following. Commented May 21, 2015 at 10:37
  • Can you update your question with precise version of Java you are using? Commented May 21, 2015 at 10:46
  • Pshemo: Question updated. Commented May 21, 2015 at 12:16
  • @Ztyx If you want someone to be notified about your comment make sure to add @nickOfThatPerson in it. Anyway what I was asking about was more about release number. I am interested if it was before or after Java 1.7.0_06 since this behaviour changed then to avoid storing original array which as you noticed couldn't be deleted by GC. Commented May 21, 2015 at 20:14
  • @Pshemo I see. Anyway, I'm running Java 1.8.0_45-b14 locally. Commented May 22, 2015 at 7:49

2 Answers 2

4

For pre JDK 7u6 version

You should use String(String) constructor in that case:

163  public String(String original) {
164 int size = original.count;
165 char[] originalValue = original.value;
166 char[] v;
167 if (originalValue.length > size) {
168 // The array representing the String is bigger than the new
169 // String itself. Perhaps this constructor is being called
170 // in order to trim the baggage, so make a copy of the array.
171 int off = original.offset;
172 v = Arrays.copyOfRange(originalValue, off, off+size);
173 } else {
174 // The array representing the String is the same
175 // size as the String, so no point in making a copy.
176 v = originalValue;
177 }
178 this.offset = 0;
179 this.count = size;
180 this.value = v;
181 }

String s = "some really looooong text";
String s2 = new String(s.substring(0,3));

When you pass result of s.substring() to String constructor, it will not use char[] of the original String. So the original String can be GC. This is actually one of the use case when one should use String constructor. While in most of the cases we should use String literal assignment.

For JDK 7u6+ version

In Java 7, implementation of String.substring() has been changed, which now internally uses String(char value[], int offset, int count) constructor (which we had to use manually in older version to avoid memory leak). This constructor checks it needs original String's value[] array or a shorter array would be sufficient. So for JDK 7+ using String.substring() will not pose memory leak issue. Please have a look at the source code String.substring()

Sign up to request clarification or add additional context in comments.

2 Comments

Interesting. My String#String constuctor looks like this: gist.github.com/JensRantil/7c08a2a0126a8f40c221 I'm running JavaSE-1.7.
Yes, you are correct. That is because in Java7 they have changed implementation of String.substring(), which now internally uses String(char value[], int offset, int count) constructor. Please have a look at the source code grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
0

Original String will always be Garbage Collected if required. No one will object. Here is the partial code for substring() method (JDK 1.7.0_51):

return ((beginIndex == 0) && (endIndex == value.length)) ? this
       : new String(value, beginIndex, subLen);

So, this method is returning a brand new String object or if beginIndex is 0 then the originam String will be returned. I guess you are concerned about first case. In that case, it has nothing to do with the older one once it is created.

4 Comments

"Here is the partial code for substring() method:" from which version of Java is this code?
@Pshemo, I have updated the exact version. Thanks! I should have mentioned it.
Then your answer is based on code from version which already corrected problem mentioned by OP java-performance.info/changes-to-string-java-1-7-0_06. Back in old days new String(int start, int end, char[] value) would simply store char[] value in substring result: grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… which prevents it from being GC.
Versions of Java starting from 7u06 are using this constructor grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… which actually copies passed char[] value into new smaller array which allows GC to remove original and big array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.