I am looking for a simple program that can demonstrate memory leak in Java.
Thanks.
http://www.codeproject.com/KB/books/EffectiveJava.aspx
See Item 6.
Memory leak are for example if you have references that are not necessary any more but can't get catched by the garbage collector.
There are simple examples e.g. from IBM that shows the principle:
http://www.ibm.com/developerworks/rational/library/05/0816_GuptaPalanki/
Vector v = new Vector();
while (true)
{
byte b[] = new byte[1048576];
v.add(b);
}
This will continuously add a 1MB byte to a vector until it runs out of memory
A great example from a great book: http://www.informit.com/articles/article.aspx?p=1216151&seqNum=6
Let's first defined what is a memory leak in Java context - it's a situation when a program can mistakenly hold a reference to an object that is never again used during the rest of the program's run.
An example to it, would be forgetting to close an opened stream:
class MemoryLeak {
private void startLeaking() throws IOException {
StringBuilder input = new StringBuilder();
URLConnection conn = new URL("www.example.com/file.txt").openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
while (br.readLine() != null) {
input.append(br.readLine());
}
}
public static void main(String[] args) throws IOException {
MemoryLeak ml = new MemoryLeak();
ml.startLeaking();
}
}
Related
Should I add a method and do not call throws in main?
Is that appropriate?
How do I write it? I do not know how to write.
private static String fileName = "C:\\fruit.csv";
public static void main(String[] args) throws
IOException{
BufferedReader br = new BufferedReader(new
FileReader(fileName));
TreeMap<String,Integer> tm = new
TreeMap<String,Integer>();
String line;
Logger logger = Logger.getLogger("Sample");
BasicConfigurator.configure();
logger.setLevel(Level.DEBUG);
try{
while((line = br.readLine()) != null){
String[] words = line.split("\\s");
for(String s : words){
if(!tm.containsKey(s)){
tm.put(s,1);
logger.debug(s+""+tm.get(s)+"N");}else{
tm.put(s,tm.get(s).intValue()+1);
logger.debug(s+""+tm.get(s)+"N");}}}
}catch(IOException e){
logger.debug("Error");
}finally{ br.close()}
Writer fw = new FileWriter("C:\\count.properties");
Properties p =new Properties();
for(String key : tm.keySet()){
p.setProperty(key,String.valueOf(tm.get(key)));
}p.store(fw,"fruit");}}}
Why is it inappropriate? Who says it is?
It entirely depends on the program, so broadly claiming that "it is inappropriate to throws at main" is wrong1.
What do you think should happen if an exception occurs? It is your decision to make, and the decision likely depends heavily on the purpose of the program.
It is an exception, so you likely want it printed, with a stacktrace so you can figure out where and why. Which is exactly what the java command does when main throws an exception, so why should you catch it, just to do the very same thing yourself?
Sure, if it is a command-line utility program, you'd likely want to catch the exception (including RuntimeException and Error), to print a one-line error message, without stacktrace, and then end the program with an exit code. But not all java programs are command-line utility programs.
1) Anyway, that is my opinion on the topic.
I have this code:
public static void main(String[] args) {
System.out.println("Reading file...");
String content = readFile(args[0]);
System.out.println("Done reading file.");
}
private static String readFile(String file) throws IOException {
BufferedReader reader = new BufferedReader( new FileReader (file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
while( ( line = reader.readLine() ) != null ) {
stringBuilder.append( line );
}
return stringBuilder.toString();
}
The readFile method works fine, well, for small files.
The thing I noticed is that it takes too much memory.
If I open the System Monitor on windows (CTRL-SHIFT-ESC), I see the java process taking up to 1,8GB RAM, while the size of my file is just 550MB.
Yes, I know, loading a file entirely into memory isn't a good idea, I'm doing this just for curiosity.
The program gets stuck at Reading file... when the newly created java process starts, it takes a bunch of MB of RAM and goes up to 1,8GB.
I also tried using String concatenation instead of using StringBuilder, but I have the exact same result.
Why does it take so much memory? Is the final stringBuilder.toString causing this?
You have to remember how these libraries work.
One byte on disk can turn into 2 byte char. The StringBuilder grows by doubling in capacity so it can be up to twice as large as you really need, and you need both the StringBuilder and String in memory at the same time.
So take your example. 550 MB can turn into 1100 MB as char alone. However, the size doubles in size so the it will be approximately the next power of two i.e. it could be 2 GB, and this is on top of a the String which would be 550 MB.
Note: the reason it is not using this much memory is that you have a bug. You are discarding all the new lines \r\n which means you have less characters.
When processing a large file where you don't have enough memory to load it into memory at once, you are better off processing the data as your read it.
BTW If you have plenty of memory, you can read the file faster, with less memory this way.
static String readFile(String file) throws IOException {
try(FileInputStream fis = new FileInputStream(file)) {
byte[] bytes = new byte[(int) fis.available()];
fis.read(bytes);
return new String(bytes);
}
}
The following code reads a bunch of .csv files and then combines them into one .csv file. I tried to system.out.println ... all datapoints are correct, however when i try to use the PrintWriter I get:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space.
I tried to use FileWriter but got the same error. How should I correct my code?
public class CombineCsv {
public static void main(String[] args) throws IOException {
PrintWriter output = new PrintWriter("C:\\User\\result.csv");
final File file = new File("C:\\Users\\is");
int i = 0;
for (final File child: file.listFiles()) {
BufferedReader CSVFile = new BufferedReader( new FileReader( "C:\\Users\\is\\"+child.getName()));
String dataRow = CSVFile.readLine();
while (dataRow != null) {
String[] dataArray = dataRow.split(",");
for (String item:dataArray) {
System.out.println(item + "\t");
output.append(item+","+child.getName().replaceAll(".csv", "")+",");
i++;
}
dataRow = CSVFile.readLine(); // Read next line of data.
} // Close the file once all data has been read.
CSVFile.close();
}
output.close();
System.out.println(i);
}
}
I can only think of two scenarios in which that code could result in an OOME:
If the file directory has a very large number of elements, then file.listFiles() could create a very large array of File objects.
If one of the input files includes a line that is very long, then CSVFile.readLine() could use a lot of memory in the process of reading it. (Up to 6 times the number of bytes in the line.)
The simplest approach to solving both of these issues is to increase the Java heap size using the -Xmx JVM option.
I can see no reason why your use of a PrintWriter would be the cause of the problem.
Try
boolean autoFlush = true;
PrintWriter output = new PrintWriter(myFileName, autoFlush);
It creates a PrintWriter instance which flushes content everytime when there is a new line or format.
Is there a better way to read Strings from an InputStreamReader.
In the Profiler im am getting a memory heap there.
public String getClientMessage() throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(tempSocket.getInputStream()));
char[] buffer = new char[200];
return new String(buffer, 0, bufferedReader.read(buffer));
}
Thanks in advance.
EDIT:
EDIT:
Messages are sent with this:
public void sendServerMessage(String action) throws IOException{
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(tempSocket.getOutputStream()));
printWriter.print(action);
printWriter.flush();
}
I would suggest you commons-io library for doing such things in a more convenient and simple way.
Just use:
return IOUtils.toString(tempSocket.getInputStream());
But this is only a code-style notice. We don't understand what do you mean by the term getting a memory heap. In any case, if you have insufficient memory troubles, you have to increase the memory for you Java application: Memory Management in the Java
HotSpot™ Virtual Machine:
Java heap space This indicates that an object could not be allocated
in the heap. The issue may be just a configuration problem. You could
get this error, for example, if the maximum heap size specified by the
–Xmx command line option (or selected by default) is insufficient for
the application. It could also be an indication that objects that are
no longer needed cannot be garbage collected because the application
is unintentionally holding references to them. The HAT tool (see
Section 7) can be used to view all reachable objects and understand
which references are keeping each one alive. One other potential
source of this error could be the excessive use of finalizers by the
application such that the thread to invoke the finalizers cannot keep
up with the rate of addition of finalizers to the queue. The jconsole
management tool can be used to monitor the number of objects that are
pending finalization.
You can use IOUtils, but it is easy to write if you can't use that library.
public String getClientMessage() throws IOException {
Reader r = new InputStreamReader(tempSocket.getInputStream());
char[] buffer = new char[4096];
StringBuilder sb = new StringBuilder();
for(int len; (len = r.read(buffer)) > 0;)
sb.append(buffer, 0, len);
return sb.toString();
}
I suspect the problem is you have no way of know from the way you send messages when a message stops. This means you must read until you close the connection which you are not doing. If you don't want to wait until you close you need to add some way of knowing when a message is finished e.g. a newline.
// create this once per socket.
final PrintWriter out = new PrintWriter(
new OutputStreamWriter(tempSocket.getOutputStream(), "UTF-8"), true);
public void sendServerMessage(String action) {
// assuming there is no newlines in the message
printWriter.println(action); // auto flushed.
}
// create this once per socket
BufferedReader in = new BufferedReader(
new InputStreamReader(tempSocket.getInputStream(), "UTF-8"));
public String getClientMessage() throws IOException {
// read until the end of a line, which is the end of a message.
return in.readLine();
}
I haven't written any Java in years and I went back to refresh my memory with a simple 'read-from-file' example. Here is my code..
import java.io.*;
public class filereading {
public static void main(String[] args) {
File file = new File("C:\\file.txt");
FileInputStream fs = null;
BufferedInputStream bs = null;
DataInputStream ds = null;
try
{
fs = new FileInputStream(file);
bs = new BufferedInputStream(bs);
ds = new DataInputStream(ds);
while(ds.available()!= 0)
{
String readLine = ds.readLine();
System.out.println(readLine);
}
ds.close();
bs.close();
fs.close();
}
catch(FileNotFoundException e)
{
e.printStackTrace();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
This compiles fine (although apparently ds.readLine() is deprected), but at runtime, this gives me
Exception in thread "main"
java.lang.NullPointerException at
java.io.FilterInputStream.available(Unknown
Source) at
filereading.main(filereading.java:21)
What gives?
You made a simple typo:
ds = new DataInputStream(ds);
should be
ds = new DataInputStream(bs);
Your code is initializing the DataInputStream with a null source, since ds hasn't been created yet.
Having said that, Jon Skeet's answer gives a better way to write a file-reading program (and you should always use Readers/Writers rather than Streams when dealing with text).
To read a text file, use BufferedReader - in this case, wrapped round an InputStreamReader, wrapped round a FileInputStream. (This allows you to set the encoding explicitly - which you should definitely do.) You should also close resources in finally blocks, of course.
You should then read lines until readLine() returns null, rather than relying on available() IMO. I suspect you'll find that readLine() was returning null for the last line in the file, even though available() returned 2 to indicate the final \r\n. Just a hunch though.
String line;
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}