我是一名初级程序员并试图理解内存泄漏的概念 - 主要是Java,因为我目前正在研究Java。是否有人能够帮助我这些例子是否是内存泄漏?
Student s1, s2;
//case I
s1 = new Student("John",20);
s1 = new Student("Mark",19);
// did I just lose the address to John, 20?
//case II:
s1 = new Student("John",20);
s2 = new Student("Mark",19);
s2 = s1;
// did I just lose the address to Mark,19?
答案 0 :(得分:1)
不,他们不是内存泄漏。分配对象时无法进行内存泄漏。因为你没有保留对第一个分配的学生(在第一个例子中)或第二个学生(在第二个例子中)的任何引用,所以这个实例可以被破坏,没有泄漏。
现在,想象一下
s1 = new Student("John",20);
myHashMap.put(s1, 33);
s1 = new Student("Mark",19);
myHashMap.put(s1, 43);
然后你保留对s1的第一个版本的引用,如果你继续创建学生并且不清理地图,那么你有内存泄漏。保存在内存中的映射是内存泄漏的常见情况。
请注意,在一个理智的java程序中发生内存泄漏并不是那么频繁。
答案 1 :(得分:0)
在C中,您必须告诉运行时恢复内存。所以程序可能如下所示:
char *pointer = malloc(1024); // ask for a chunk of memory
doSomethingWith(pointer); // something using the memory
free(pointer);
pointer = malloc(2048); // ask for another chunk of memory
doSomethingWith(pointer); // something using the memory
free(pointer);
如果您未能调用free(),那么该块内存将在程序的生命周期内保持使用:
char *pointer = malloc(1024); // ask for a chunk of memory
doSomethingWith(pointer); // something using the memory
pointer = malloc(2048); // ask for another chunk of memory
在上面的代码中,假设doSomethingWith()
没有将其保存在某处,我们丢失了指向1024字节块的指针,因为我们为pointer
分配了一个新值。没有这个价值,我们就无法释放那段记忆。
正如您可以想象的那样,在实际代码中,除非您保持非常有条理,否则很容易丢失所有指针。当代码遵循其快乐路径时,您可以很好地释放内存,但是当它处理错误(找不到文件;主机不可用等)时,它可能会错过free()
。这就是导致程序逐渐消耗越来越多无法释放的内存的原因。
char *buffer = malloc(1024);
ssize_t size = read(filehandle,buffer,1024,0)
if( size != -1 ) {
doSomethingWith(buffer);
free(buffer);
} else {
perror("Error: ");
// oops, we have not free()d buffer
}
这称为内存泄漏。
在Java中,new
大致相当于malloc
,并且没有free()
。相反,JVM的一部分称为垃圾收集器,它跟踪每个对象,以及每个对象(或者用C语言,“指针”)。当GC决定没有线程直接或间接引用特定对象时,它会回收该对象占用的内存。
因此:
Person p = new Person("John"); // "John" won't be GCd because p refers to it
p = new Person("Peter"); // Now nothing refers to "John" to the GC can clear it away
当参考文献超出范围时,参考文献也不复存在:
Person someMethod() {
Person p1 = new Person("John");
Person p2 = new Person("Peter");
return p2; // the caller will probably use the reference to p2,
// but after this method ends, p1 is definitely available
// for GC.
}
所有这些意味着编写泄漏内存的Java程序非常困难。
垃圾收集器会定期进行清理,您可以使用 VisualVM 等工具查看它。你会得到一个“锯齿”的效果,每次GC运行时内存使用量会累积,然后急剧下降。
在Java中泄漏内存的一种方法是将引用存储在您不需要的某些结构中,或者不能正确维护。
Person p = new Person("John");
irrelevantSet.add(p);
p = new Person("Peter");
此处,GC无法清除“John”,因为irrelevantSet
包含对它的引用。通常你将一个对象放在一个像Set这样的结构中,因为你没有想要它被清除掉;但是你有时会遇到这样的情况,即你忘记那些你真的不需要你的程序的对象,仍然保留在一个结构中。
你的例子:
Person p1 = new Person("John");
Person p2 = new Person("Peter");
p1 = p2; // p1 = p2 = "John". "Peter" will be GCd.
使用这样的行看Java代码并不罕见:
Person p1 = new Person("John");
doSomethingWith(p1);
p1 = null; // let the GC take back the Person
但是如果你正确地构造代码 - 使用局部变量和简短方法 - 这不应该是必要的,我认为这样做不好。
答案 2 :(得分:0)
不,您的代码没有内存泄漏。
您可以使用visualvm自行分析。
请参阅更多信息:http://www.javaworld.com/article/2072864/heap-dump-and-analysis-with-visualvm.html