【问题标题】:How is memory managed while loading classes in Java?在 Java 中加载类时如何管理内存?
【发布时间】:2015-05-27 06:56:14
【问题描述】:

假设我有一个包含 10 个方法的类,我需要从该类中实例化 10 个对象。 问题是:JVM 是否会在创建对象时为 10 个实例分配 10 个不同的内存空间(我的意思是在我调用构造函数时,即 new MyClass(); ? 或者它会加载一次类定义在内存和每个实例中调用这 10 个方法中的每一个时,在运行时,JVM 会分配内存吗?

为了消除一些误解,我的问题是在创建对象时,我知道所有数据成员都分配在堆内存中,但我不确定尚未调用的方法是否在内存中分配不同每个对象与否?

【问题讨论】:

  • 方法不需要为每个实例单独分配;他们只是加载了类。

标签: java jvm


【解决方案1】:

JVM 会在创建对象时为 10 个实例分配 10 个不同的内存空间(我的意思是在我调用构造函数时,即 new MyClass();

它可能会这样做,但是通过逃逸分析,它可以将它们放在堆栈上或完全消除它们。

或者它会在内存和每个实例中加载一次类定义,同时调用这 10 个方法中的每一个,在运行时,JVM 将分配内存?

如果您有一个 ClassLoader,您将获得该类的一个实例,但是如果每个实例都有自己的 ClassLoader,您将在每个 ClassLoader 中获得该类的副本。注意:每个 ClassLoader 可以有不同版本的同名类。

为了澄清一些误解,我的问题是在创建对象时,我知道所有数据成员都分配在堆内存中,

它存储在 PermGen (Java

实际实例理论上是添加到堆中的,但不是必须的。

我不确定尚未调用的方法是否在每个对象的内存中分配不同?

JVM 经历了许多优化阶段,当您调用一个方法时,它可能会对其进行优化、内联甚至消除它。您可以通过在命令行中添加 -XX:+PrintCompilation 来查看正在编译(甚至重新优化)的方法。

【讨论】:

  • 我们能否证明发生了堆栈分配而不是堆分配?
  • @TheLostMind 您可以看到没有产生垃圾。一个简单的例子是使用 lambdas,因为它很容易被消除。如果你用一个小堆重复运行一些琐碎的代码,你会看到 GC 直到代码优化-XX:+PrintCompliation(打印方法已编译)和-XX:BCEATraceLevel=3(打印已执行转义分析)之后你可以如果所有对象都放在堆栈上,请查看没有 GC。您还可以使用飞行记录器查看对象的创建时间。
【解决方案2】:

是的。 类元数据被加载到Permgen空间(Java8中的MetaSpace)。因此,一旦类加载,所有方法都可用(静态和非静态)。尚未调用的方法也将作为此元数据的一部分加载。所有方法只会加载一次。

【讨论】:

    【解决方案3】:

    在加载类时,类的所有方法(静态和非静态)也会加载到内存中。不管有多少都在加载。

    JVM 会为每个对象分配不同的内存位置。

    假设

    MyClass m1 = new MyClass(); // one memory location
    
    MyClass m2 = new MyClass(); // different location
    
    MyClass m3 = m1; // same memory location of m1 object
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多