Reputation: 1
I've got problem with releasing memory by jvm. I know that java release memory of thread resoruces after its exit from run method. And other objects are deleting by garbage collector when they don't have referencees with some exceptions like windows/frames. Why in below code gc doesn't release memory of byte array despite of threads end their work? I know System.gc() is only suggestion for gc but i use it just in case and assigning null for byte array reference is unnecessary.
Below code is only example and i've got real problem in my client-server application in similar case when server send files to clients.
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
int j=0;
for (int i=0;i<5;i++){
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
j++;
new Thread(new Runnable(){
public void run(){
byte[] bytes=new byte[1024*1024*100];
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("exiting "+Thread.currentThread().getName());
bytes=null;
System.gc();
}
}, ""+j).start();
}
System.gc();
}
I leave above problem and go to be practical. Earlier there was loading whole file to one byte array and sending it using writeObject(), but it causes memory problems. Look at that code:
BufferedOutputStream bos = null;
byte[] bytes;
int count;
for (int i = 0; i < filesToUpdate.size(); i++) {
if (mapp.get(filesToUpdate.get(i)) == null) {
addNewFile(filesToUpdate.get(i));
}
bos = new BufferedOutputStream(new FileOutputStream(new File(filesToUpdate.get(i))));
long bufferSize = ois.readLong();
ous.writeObject(2);
ous.flush();
bytes =new byte[8192];
while ((count=ois.read(bytes))>0){
bos.write(bytes, 0, count);
}
bos.flush();
bos.close();
ous.writeObject(3);
ous.flush();
}
ois.readObject();
updateRevision(mapp, filesToUpdate);
It's client side which receives files. READ METHOD BLOCKS in first file after it received last packet. And here is server side:
int count;
File file;
FileInputStream fis=null;
byte[] bytes;
for (int i=0;i<filesForPatch.size();i++){
if (pc.getWhat()==0)
path="admin/";
else path="client/";
path+=filesForPatch.get(i);
file=new File(path);
long buffSize=file.length();
ous.writeLong(buffSize);
ous.flush();
ois.readObject();
fis=new FileInputStream(file);
bytes=new byte[8192];
while ((count=fis.read(bytes))>0){
ous.write(bytes, 0, count);
}
ous.flush();
fis.close();
ois.readObject();
}
Any ideas how to solve this problem?
Upvotes: 0
Views: 2896
Reputation: 43052
for (int i=0;i<5;i++){
This most likely is an insufficient amount of time for the GC to settle into a stable state for heap size. If you were to run this 10000 times you would see that it eventually settles on a stable amount of memory.
So your example is not a reduced test case of your client-server program.
So if there is an actual memory in your application it is not possible to find it based on that example.
The easiest way to find a leak is to let the program run for a while and then inspect a heap dump with a memory profiler such as yourkit, jprofiler or eclipse's MAT
Upvotes: 0
Reputation: 200158
The info you get from the Windows Task Manager doesn't mean a lot. The JVM dynamically sizes the heap according to many factors, throughput being the first concern. The heap size is never exactly equal to the actual memory allocated by reachable objects.
If you want to observe the effects of garbage collection, then connect to your JVM with VisualVM. For best effects install the VisualGC plugin and open its tab, there you will be able to observe the changes in the size of all generations in real time. Garbage collections will be immediately reflected in the shown occupancy and you'll also be able to notice when the heap itself is being resized (rarely).
Upvotes: 1