我经常被问到这个问题。如何回答才算得上是一个好方法呢?
我经常被问到这个问题。如何回答才算得上是一个好方法呢?
那么,问题在于Java应用程序或库可以通过本地代码分配离堆对象,这些对象需要手动管理。如果应用程序/库有错误或使用不当,则可能会出现本地内存泄漏。 (例如:Android位图内存泄漏 ...请注意,此问题已在较新版本的Android中得到解决。)
1 - 我提到了一些事情。一些托管语言允许您编写非托管代码,从而可以创建经典的存储泄漏。 一些其他托管语言(或更准确地说是语言实现)使用引用计数而不是适当的垃圾回收。 基于引用计数的存储管理器需要某些东西(即应用程序)来打破循环......否则将导致存储泄漏。
是的,即使你有垃圾回收机制,内存泄漏仍然可能发生。例如,您可能会保留一些需要手动关闭的资源,例如数据库结果集。
* - 为解决最后一个问题花费了数十亿咨询费用。
是的,从某种意义上说,您的Java应用程序可以随着时间推移累积内存,垃圾回收器无法释放该内存。
通过保留对不需要/不想要的对象的引用,它们永远不会超出范围,其内存也不会被回收。
是的,如果您不取消引用对象,它们将永远不会被垃圾回收,并且内存使用量将增加。但是由于Java的设计方式,这很难实现,而在其他一些语言中,有时很难避免这种情况。
编辑:阅读Amokrane的链接。它很好。
是的,这是可能的。
在《Effective Java》中,有一个涉及使用数组实现堆栈的示例。如果您的弹出操作仅仅是将索引值减小,那么就可能会出现内存泄漏。为什么?因为您的数组仍然引用了已弹出的值,而您仍然引用了堆栈对象。因此,对于这个堆栈实现来说,正确的做法是使用显式的null赋值清除弹出数组索引处的值的引用。
是的,在某些情况下可以这样做,例如当程序错误地保留了一个不再使用的对象的引用,因此它没有被垃圾回收器清除。
一个例子就是忘记关闭已打开的流:
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();
}
}
书籍《Effective Java》给出了两个关于“内存泄漏”的原因: