I'm writing a simple program to read and decode binary file to string and output to a textfield. For construct the string I used Stringbuilder
. However I notice that each time my function is called, the memory usage of the app is increase and isn't reduced even after the function is done due to the Stringbuilder
object.
I'm not really sure if it is the memory leak or not.
I'm new to Java btw.
Here is my code:
public class Reader {
final StringBuilder builder = new StringBuilder();
public void ProcessFile(String path, JTextArea area) {
try {
// TODO code application logic here
final FileChannel channel;
channel = new FileInputStream(path).getChannel();
MappedByteBuffer buffer = enter code herechannel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
while(buffer.remaining() > 0) {
int totalLength = buffer.getInt();
buffer.position(buffer.position() + 1);
buffer.position(buffer.position() + 7);
long timestamp = buffer.getLong();
int protocol = buffer.get() & 0xFF;
buffer.position(buffer.position() + 1);
int dataLength = buffer.getInt();
switch(protocol) {
case 0x00:
//General
byte processorID = buffer.get();
byte compID = buffer.get();
short domainID = buffer.getShort();
short channelID = buffer.getShort();
int threadID = buffer.getInt();
String level = levelToString(buffer.get());
buffer.position(buffer.position() + 1);
short textLength = buffer.getShort();
byte[] textArray = new byte[textLength];
buffer.get(textArray, 0, textLength);
String text = new String(textArray);
builder.append(timestamp)
.append(", general, ")
.append(dataLength)
.append(", ")
.append(String.format("0x%02X",processorID))
.append(", ")
.append(String.format("0x%02X",compID))
.append(", ")
.append(String.format("0x%2X",domainID))
.append(", ")
.append(String.format("0x%2X",channelID))
.append(", ")
.append(String.format("0x%2X",threadID))
.append(", ")
.append(level)
.append(", ")
.append(text)
.append("\n");
break;
case 0x01:
//Binary
byte[] binaryArray = new byte[dataLength];
buffer.get(binaryArray, 0, dataLength);
String binaryLog = bytesToHex(binaryArray);
builder.append(timestamp)
.append(", vw-hmi-bin, ")
.append(dataLength)
.append(", ")
.append(bytesToHex(binaryArray))
.append("\n");
break;
default:
//Do nothing
break;
}
}
area.setText(builder.toString());
builder.setLength(0);
builder.trimToSize();
channel.close();
} catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
}
private final char[] hexArray = "0123456789ABCDEF".toCharArray();
private String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public void OutputToFile(String path, String content) throws Exception{
try (PrintWriter writer = new PrintWriter(path, "UTF-8")) {
writer.println(content);
writer.close();
}
}
private String levelToString(byte level) {
String levelString = null;
int levelValue = Math.abs(level);
switch(levelValue) {
case 0:
levelString = "All";
break;
case 32:
levelString = "Trace";
break;
case 64:
levelString = "Debug";
break;
case 96:
levelString = "Normal";
break;
case 128:
levelString = "Info";
break;
case 160:
levelString = "Warn";
break;
case 192:
levelString = "Error";
break;
case 224:
levelString = "Fatal";
break;
}
return levelString;
}
}
The best way is to enable verbose GC logs, and then track the timings at which full GC is triggered which basically covers the GC for young, survivor and tenured generation (your string builder object might be held up in any of these areas).
So still after the full GC, if you see that the memory is not freed up, then the best tool will be to use eclipse MAT and track which objects are occupying memory.
Lets say if you find a Object X of class X which holds most memory, then you can analyse the object or the class. Eclipse MAT will also give you option to see what data your object is holding.
So I would suggest you not to go through by this heap size that you are tracking. But enable the verbose GC logs. Analyse them, and still if you find any issue then analyze through profiling tools like JvisualVM, eclipse MAT, Java Mission Controller etc
Google up about verbose GC logs and how you can enable them