我有通过jvm释放内存的问题。我知道java的释放内存在线程从run方法退出后会被重新调整。当其他对象没有引用时会被垃圾回收器删除,例如windows / frames等。为什么在下面的代码gc不释放字节数组的内存尽管线程结束他们的工作?我知道System.gc()只是gc的建议,但是我只是为了以防万一,并且为字节数组引用分配null是不必要的。
下面的代码只是示例,在我的客户端 - 服务器应用程序中,当服务器向客户端发送文件时,我遇到了真正的问题。
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();
}
我留下上面的问题并且变得实用。之前有将整个文件加载到一个字节数组并使用writeObject()发送它,但它会导致内存问题。看看那段代码:
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);
它是接收文件的客户端。收到最后一个数据包后,在第一个文件中读取METHOD METHOD BLOCKS。 这是服务器端:
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();
}
任何想法如何解决这个问题?
答案 0 :(得分:1)
从Windows任务管理器获取的信息并不意味着很多。 JVM根据许多因素动态调整堆的大小,吞吐量是首要考虑因素。堆大小永远不会完全等于可达对象分配的实际内存。
如果要观察垃圾收集的影响,请使用VisualVM连接到JVM。为了获得最佳效果,请安装VisualGC插件并打开其选项卡,您可以在那里实时观察所有世代的大小变化。垃圾收集将立即反映在显示的占用率中,您还可以注意到堆本身的大小调整(很少)。
答案 1 :(得分:0)
for(int i = 0; i&lt; 5; i ++){
这很可能是GC没有足够的时间来稳定堆大小的稳定状态。如果你要运行10000次,你会发现它最终会稳定在一个稳定的内存中。
因此,您的示例不是客户端 - 服务器程序的简化测试用例。
因此,如果您的应用程序中存在实际内存,则无法根据该示例找到它。
找到泄漏的最简单方法是让程序运行一段时间,然后使用内存分析器检查堆转储,例如yourkit,jprofiler或eclipse's MAT