正如我在某处读到的那样,创建实例时会分配内存并从堆中分配空间。如果它是正确的,那么在实例和对象创建期间分配内存的时间和数量是多少?
最佳答案
方法中声明的变量存储在栈中,而实际对象存储在堆中。考虑
Integer a = new Integer(10);
在此示例中,在堆上创建了一个 Integer 类型的对象,并返回一个引用(32 位或 64 位)并将其作为变量“a”存储在方法堆栈中。如果 JVM 喜欢优化,它可以自由地将这样的变量保存在 CPU 寄存器中。
当使用 new 关键字时,对象的内存被分配。它通常在 TLAB 内分配。 (线程本地分配缓冲区)是 eden heap 的一部分保留给正在运行的线程。从而将对象分配的开销减少为简单的“指针碰撞”。不使用 TLAB 的两种情况是 1) 当对象对于剩余空间来说太大时,在这种情况下它将直接提升到 old gen。和 2) 当支持的 JVM 通过 escape analysis 决定时它可以完全避免对象并直接分配到堆栈上(或者甚至将对象分开并仅分配堆栈上所需的字段)。
保留的内存量由对象头组成,通常为 2 words (数组为 3),然后是对象及其父类中声明的每个字段的空间。这些字段的总大小取决于 JVM 和底层平台(例如 32 位或 64 位)以及压缩引用等 JVM 配置。
------------------+------------------+------------------ +--------------------------
| mark word | klass pointer | array size (opt) | padding and fields |
------------------+------------------+-------------------+--------------------------
官方不支持向 JVM 询问大小,但是 EHCache sizeOf是一个非常好的“最佳猜测”,它使用不同 JVM 的知识并通过使用 Java Unsafe 访问底层指针。 .
了解每个字段大小的起点是 size of primitives defined by the Java language ,但是这只是最小大小,因为 JVM 设计为使用 32 位,因此小于此的原语通常被填充为 32 位。例如 boolean 值。
字段的确切布局会因 JVM 的不同而有所不同,但它们往往会按照定义它们的类从继承树的根开始进行分组。例如,考虑
和
上面的图片都来自这个很好的blog post很好地描述了内存布局,
关于java - 在实例创建或使用 new 关键字创建对象期间何时分配内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25055375/