I have android application which takes huge String Object from telnet client. Later I Use only small part of the big String. I use
new String(Part of old string);
To separate new string Char array from old Strings char array. So the old String Should get garbage collected, but new string surprisingly still has an reference to the old object.
I can see it with “Eclipse Memory Analyzer”.
And that overflows my tiny 16Meg application memory quickly.
How to avoid that situation?
private WifiChannel parse1(String channLine){
//scanning with "iwlist wlan0 scanning" the getChans1 method
String[] input = channLine.split(System.getProperty("line.separator"));
if (input.length < 4);
String segment[];
String segment2[];
WifiChannel chan = new WifiChannel();
try {
if (input.length > 5){
chan.setMacAddress(new String(input[0]));
segment = input[1].split(":");
chan.setChannel(Integer.parseInt(segment[1].trim()));
segment = input[3].split(" ");
segment2 = segment[20].split("=");
chan.setQuality(new String(segment2[1]));
segment2 = segment2[1].split("/");
chan.setSignalStrength((Integer.parseInt(segment2[0].trim())*100)/Integer.parseInt(segment2[1].trim())+"%");
segment2 = segment[23].split("=");
try{chan.setSignalLevel(Integer.parseInt(segment2[1].trim()));}catch(Exception e){chan.setSignalLevel(0);}
segment = input[5].split(":");
chan.setName(new String(segment[1].replaceAll("^\"|\"$", "")));
for (int i = 6;i<input.length;i++)
if (input[i].contains("Mode"))
segment = input[i].split(":");
chan.setChannelMode(new String(segment[1]));
String band = "";
if(channLine.contains("5.5 Mb/s"))band = band +"b";
if(channLine.contains("12 Mb/s") )band = band +"g";
chan.setBand(new String(band));
}
}catch (Exception e){Log.e("","",e);}
return chan;
}
Method input is also part of bigger String.
Every String instance is backed by a char array:
Because of efficiency reasons, some operations on a string can can create a new string instance that shares the
char[]with the original string. This is possible because all strings are immutable. An example of this is thesubstring()method:The line with my comment added calls a constructor that doesn’t create a copy of the
char[], but directly references it. You can’t call this constructor directly, because it is package-private and therefore it is used only internally by methods such as substring:Now, if you create a short substring from a very long string, then the short one still references the original large
char[]. Even after the original string is garbage collected, its large array still stays in the memory, even though only only a small portion of it is now accessible by the new substring. This effectively creates a memory leak.To fix this problem, the usual technique is to create a new string from the substring using the copy constructor, which makes a copy of only the needed range of the original
char[].Edit:
For completeness, this is the source of the copy-contructor. As you can see, if the original string references an array of the same length as of the string itself, then the array doesn’t need to be copied, because there are no “dead characters” in it. However, if the array is larger then the length of the string, then a copy of the “live” range of the array is performed.
Note:
All the above source code comes from Android API 15