【问题标题】:Can using too many static variables cause a memory leak in Java?使用过多的静态变量会导致 Java 中的内存泄漏吗?
【发布时间】:2010-10-13 02:11:04
【问题描述】:

如果我的应用程序有太多静态变量或方法,那么根据定义,它们将存储在堆中。如果我错了,请纠正我

1) 在应用程序关闭之前,这些变量会一直在堆上吗?
2) 它们是否随时可用于 GC?如果不是,我能说这是内存泄漏吗?

【问题讨论】:

    标签: java memory-management memory-leaks


    【解决方案1】:

    如果您有一个静态哈希图并向其中添加数据...数据将永远不会消失并且您有泄漏 - 以防您不再需要数据。如果你需要数据,那不是泄漏,而是一大堆内存。

    【讨论】:

    • 假设静态 hashmap 有很多对象;我将地图的引用设为空(不是它包含的所有对象)?是内存泄漏吗?既然你已经说过“类加载器永久持有一个静态引用,因此 GC 永远不会启动”?
    • 如果您将静态引用设置为 null 并且您没有在其他任何地方引用该映射,则内存将被释放。如果其他人没有引用该映射中的引用对象,它们也将被释放。
    【解决方案2】:

    静态方法只是方法,它们不存储在堆中,它们只是不能使用“this”参数。

    静态变量充当 GC 的“根”。因此,除非您将它们显式设置为 null,否则它们将与程序存在一样长,因此可以从它们访问的所有内容。

    仅当您打算让内存变得空闲并且它没有变得空闲时,才会将这种情况视为内存泄漏。如果您打算让您的静态变量在部分时间内包含对对象的引用,并且在完成该对象时忘记将其设置为 null,那么您最终可能会出现泄漏。但是,如果您将它放在静态变量中并打算在程序运行时一直存在,那么它绝对不是泄漏,它更有可能是“永久单例”。如果该对象在您希望它仍然存在时被回收,那将是非常糟糕的。

    关于堆的问题:Java 中的所有对象要么存在于堆上,要么存在于堆栈上。使用 new 运算符在堆上创建对象。然后将参考附加到它们。如果引用变为 null 或超出范围(例如,块结束),GC 会意识到无法再次到达该对象并回收它。如果您的引用在静态变量中,它永远不会超出范围,但您仍然可以将其设置为 null 或另一个对象。

    【讨论】:

    • IIRC 静态字段将在声明它们的类被 GC 后立即被 GC。如果类的最后一个实例消失了,则类声明将消失,静态字段也将消失。
    • 我不确定@o11rig 是否完全准确,但我相信在某些情况下允许 GC 为没有成员的类收集静态数据。我从几个来源听说过,但从未听到过确切的解释。
    • 小问题:所有 Java 对象 都存在于堆中。如果对象引用和原语是当前执行方法的局部变量,则它们可以存储在堆栈中,否则存储在堆中。 (除了在任何带有 JIT 的现代 JVM 中,JIT 的优化器可以将对象放在任何它喜欢的地方,只要它仍然像对象在堆上一样行为。)可以说静态方法——或者至少是实现它们的 Java 字节码——也存在于堆中,作为代表定义它们的类的 Class 对象的一部分。
    【解决方案3】:

    静态直接或间接引用的对象将保留在堆上,直到可以收集适当的类加载器。在某些情况下(例如 ThreadLocal),其他对象间接引用类加载器导致它保持未被收集。

    例如,如果您有一个静态列表并动态添加对它的引用,那么您很容易以“对象生命周期争用问题”告终。出于多种原因,请避免使用可变静态。

    【讨论】:

    • 在类成员中使用静态看起来像可能的泄漏吗?:private static final Function r = (status) -> {return new Object();};
    • @Ajeetkumar 不,这是一个不可变的字段。它所引用的只是FunctionStringObject 和类本身(通过方法引用)。
    【解决方案4】:

    它不会导致经典 C 意义上的内存泄漏...例如

    Class A{
    
    static B foo;
    
    ...
    
    static void makeFoo(){
       foo = new B();
       foo = new B();
    }
    

    在这种情况下,调用 makeFoo() 不会导致内存泄漏,因为第一个实例可以被垃圾回收。

    【讨论】:

      【解决方案5】:

      只要您可以从代码中的某处引用这些变量,GCed 就不能,这意味着它们将一直存在,直到应用程序结束。

      你能称之为内存泄漏吗,我不会称之为内存泄漏,通常内存泄漏是你通常希望恢复但你从未这样做的内存,或者你只恢复了它的一部分。此外,内存泄漏通常会随着时间的推移变得更糟(例如:每次调用方法时都会“泄漏”更多内存),但是在这种情况下,这些变量的内存使用量是(某种)静态的。

      【讨论】:

      • 不需要从你的代码中引用静态变量...类加载器永久持有一个引用,因此 GC 永远不会启动。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-17
      • 2021-09-22
      • 2023-03-28
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多