使用 Static 是否更好地进行内存管理?

Is using Static better to memory management or not?

在一些像this and this这样关于静态的文章和教程中,据说使用静态有利于内存管理,因为静态变量在class区域只在[时获取内存一次class加载中。

但是我的朋友告诉我静态方法保存在堆栈中,因为管理堆比堆栈更容易,垃圾收集器只在堆上工作,只要应用程序是 运行 堆栈就不会被清理,尽量少用静态方法。

注意:

我在 Whosebug 中阅读了关于堆栈内存的相同问题,但我没有得到太多,因为它们使用 "PermGen space" 和其他我不知道的词是多么复杂和专业。

我希望有人简单地解释一下我的朋友预付款是否正确?

而且我知道这取决于情况,想象一下我可以使用静态方法或不使用静态方法进行设计。内存管理讨论哪一种方法更好?

答案是:问这个问题说明你把时间和精力花在了错误的地方。

获得 Java 表现良好的应用程序的关键作用:想出一个优雅的 OOP 设计,以直接的方式实现您的要求。

您必须了解 "Java performance magic" 几乎完全发生在 运行 时间 通过即时编译器的工作。而JIT最擅长的是那些我们认为"best practices" in Java的常用模式。

尝试提出 "special" 像 "lets use static all over the place" 这样的想法最终甚至可能导致更差的性能 - 因为您的 "special" 代码阻止了 JIT 以最佳方式完成它的工作方法。

因此:分别信任 JIT 和 GC。并确保这些工具能够以 "optimal" 的方式工作,方法是……其他人都在做的事情!

不要让这种过早优化的想法毁了您的 OOP 设计。即使您的应用程序属于需要 密集 低级优化的罕见类别 - 那么您只有一种方法:研究 GC 和 JIT 的工作原理 深入

换句话说:这些问题不是真正的问题。含义:

  • 当然你会避免完全愚蠢的错误但是
  • 否则您 不会 担心内存或性能问题 除非 您有 真正的手头的问题(例如,应用程序需要太多内存或客户向您投诉)。

然后 - 当您 运行 遇到 "real" 问题时:您必须 配置文件 您的应用程序以了解问题的根本原因。再次重申:您不允许这种过早的(未受过教育的)优化想法以负面方式影响您的设计。

而且评论暗示我不够清楚:当你遇到真正的记忆问题时,那么你绝对 必须理解像 "perm generation" 这样的术语。因为那时您必须详细了解 GC 的工作原理。说真的:相信这里的人告诉你 static 关键字在创建 "memory efficient" 应用程序中没有发挥任何重要作用。

静态变量的内存分配只在程序第一次运行时发生一次。 如果您在 class 中使用它,那么只会创建一个实例,该实例由 class 的每个对象共享。 所以内存消耗是 less.Before java8 静态方法和变量存储在 PERMGEN space.But 现在他们引入了新内存 space 称为 METASPACE 现在这是所有 class方法,存储class的字段和常量池。 有关 METASPACE 的更多详细信息,请访问:"https://dzone.com/articles/java-8-permgen-metaspace"

简短的回答是你的朋友错了。 class 对象本身(即 java.lang.Class<T> 的实例未分配在堆栈上。 Java 加载 classes 并且不会在加载它们的函数结束时卸载它们,因此不能进入堆栈。此外,所有线程都访问相同的 class 对象,但每个线程都有自己的堆栈 space.

警告:此答案的其余部分讨论了 JVM 实现细节和垃圾回收内存管理。大多数应用程序不需要考虑这些事实,也不能依赖它们来保证程序的正确性,因为它们可以并且确实会随着版本的不同而发生变化。

许多现代 JVM 使用分代垃圾收集器,并且因为加载的系统 classes 不会被卸载,所以可以将它们放在一个称为 'Permanent Generation' (PermGen) 的区域中,该区域在 Java 8 由 Oracle 替换为 MetaSpace,其中包含问题所指的 class 元数据。但请注意,这些是 Oracle JVM 的实现细节,而不是 Java 规范的一部分。

另一个可能的混淆是,这都适用于 class 直接要求的 space,它是静态引用,而不是那些引用所指的内容。

class Sample {
    private static BigThing biggie=new BigThing(10000);
}

在示例中,对象 biggie 引用将像其他任何内容一样在堆上创建。实际上它没有在这里声明 final 并且可以引用在执行过程中任何时候创建的任何对象,因为它可以被重新分配。

这是一篇关于该主题的较新文章:

https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace

请注意 JVM 的这个区域多年来一直在变化和调整,但(据我所知)在 Java 9 中没有变化。