当前位置: 首页 > 面试题库 >

即使每个字段都是4字节对齐的,为什么Java对象中也存在内部碎片?

吴驰
2023-03-14
问题内容

介绍:

我使用JOL(Java对象布局)工具来分析Java对象的内部和外部碎片,以进行研究。

这样做时,我偶然发现了以下内容:

x@pc:~/Util$ java -jar jol-cli-0.9-full.jar internals sun.reflect.DelegatingClassLoader
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

Instantiated the sample instance via sun.reflect.DelegatingClassLoader(java.lang.ClassLoader)

sun.reflect.DelegatingClassLoader object internals:
 OFFSET  SIZE                                     TYPE DESCRIPTION                               VALUE
      0     4                                          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                                          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                                          (object header)                           3b 13 00 f8 (00111011 00010011 00000000 11111000) (-134212805)
     12     4                    java.lang.ClassLoader ClassLoader.parent                        null
     16     4   java.util.concurrent.ConcurrentHashMap ClassLoader.parallelLockMap               null
     20     4                            java.util.Map ClassLoader.package2certs                 (object)
     24     4                         java.util.Vector ClassLoader.classes                       (object)
     28     4           java.security.ProtectionDomain ClassLoader.defaultDomain                 (object)
     32     4                            java.util.Set ClassLoader.domains                       (object)
     36     4                        java.util.HashMap ClassLoader.packages                      (object)
     40     4                         java.util.Vector ClassLoader.nativeLibraries               (object)
     44     4                         java.lang.Object ClassLoader.assertionLock                 (object)
     48     4                            java.util.Map ClassLoader.packageAssertionStatus        null
     52     4                            java.util.Map ClassLoader.classAssertionStatus          null
     56     8                                          (alignment/padding gap)                  
     64     1                                  boolean ClassLoader.defaultAssertionStatus        false
     65     7                                          (loss due to the next object alignment)
Instance size: 72 bytes
Space losses: 8 bytes internal + 7 bytes external = 15 bytes total

题:

在这种情况下,令我困扰的是每个字段都是4字节对齐的(请参见OFFSET列),但是仍然在偏移量56处添加了对齐间隙(56 8 (alignment/padding gap))。我在Java 9中进行了相同的html" target="_blank">测试,并且对象布局发生了一些变化,alignemnt /
padding间隙仍然存在,但是甚至有12个字节大。

为什么会这样呢?为什么它有8个字节大,我看到的所有其他对象在内部都是4个字节对齐的?我自己找不到解释。

我的系统:

openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

使用默认设置(带有压缩oop的ParallelOldGC)


问题答案:

有时,HotSpot注入内部特定于VM的字段,这些字段在Java级别不可见。在ClassLoader情况下,这是一个指向ClassLoaderData

#define CLASSLOADER_INJECTED_FIELDS(macro)                            \
  macro(java_lang_ClassLoader, loader_data,  intptr_signature, false)

这是一个intptr_t类型的字段,即恰好8个字节长。

这是HotSpot源描述
ClassLoaderData的方式:

// A ClassLoaderData identifies the full set of class types that a class
// loader's name resolution strategy produces for a given configuration of the
// class loader.
// Class types in the ClassLoaderData may be defined by from class file binaries
// provided by the class loader, or from other class loader it interacts with
// according to its name resolution strategy.
//
// Class loaders that implement a deterministic name resolution strategy
// (including with respect to their delegation behavior), such as the boot, the
// extension, and the system loaders of the JDK's built-in class loader
// hierarchy, always produce the same linkset for a given configuration.
//
// ClassLoaderData carries information related to a linkset (e.g.,
// metaspace holding its klass definitions).
// The System Dictionary and related data structures (e.g., placeholder table,
// loader constraints table) as well as the runtime representation of classes
// only reference ClassLoaderData.
//
// Instances of java.lang.ClassLoader holds a pointer to a ClassLoaderData that
// that represent the loader's "linking domain" in the JVM.
//
// The bootstrap loader (represented by NULL) also has a ClassLoaderData,
// the singleton class the_null_class_loader_data().


 类似资料:
  • 我想创建对象MyObject的实例,其中的每个字段都是该字段值的总和 我创建一个对象 然后我构建对象列表: 我想要创建对象() 很容易对每个流求和一个字段: 或 然后构造对象

  • 它向任何对象添加。为什么?对象上没有属性... 第二个示例演示了一个问题--当我悬停在表达式中的绑定名称上时,IntelliSense会向我显示一个弹出窗口,其中位于花括号内,因此很容易假设对象具有属性,不是吗?您不同意IntelliSense应该显示内容吗?

  • 问题内容: 我需要存储大量的日期(可能足够大,以至于需要考虑使用的堆空间量,因此请不要讲授过早的优化),我想知道使用某种原始表示是否有意义java.util.Date(或其他一些现有的Date类)的形式。我知道我可以进行一些性能分析来尝试一下,但是有人知道一个Date对象使用多少字节的内存吗? 问题答案: 我的直觉反应是Date的内存开销非常小。检查源代码,似乎该类仅包含一个实例字段(长为毫秒)。

  • 我在内存中有大量64位值。不幸的是,它们可能无法与64位地址对齐。我的目标是更改所有这些值的endianess,即交换/反转它们的字节。 我知道bswap指令交换32位或64位寄存器的字节。但由于它需要一个register参数,我无法将内存地址传递给它。当然,我可以先将内存加载到寄存器中,然后交换,然后再写回: 但考虑到地址可能未对齐,这是否正确? 另一种可能性是手动进行交换: 这显然是更多的指示

  • 我目前所能理解的是: 内部插槽不是属性 内部插槽在创建对象期间使用,但不添加到对象本身 内部插槽是或具有值,最初

  • 本文向大家介绍为什么字符串对象在Java中是不可变的?,包括了为什么字符串对象在Java中是不可变的?的使用技巧和注意事项,需要的朋友参考一下 通常,字符串用于表示重要细节,例如数据库连接URL,用户名密码等。字符串的不变性有助于使这些细节保持不变。 类似地,在加载类时,将String用作参数。那时,更改字符串可能会导致加载错误的类。 如果不可变,则变量(字符串)自动为线程安全的。