我研究了以下内容。对象头由一个标记字和一个klass指针组成。在数组的情况下,它还额外有size头。换句话说,对象数据的头中没有大小信息,那么JVM在阅读对象数据时,如何知道从起始地址读取多远呢?
dtcbnfnu1#
数组和“普通”对象的区别在于数组可以有不同的大小,而给定类的每个对象都有相同的大小。在某种程度上,非数组对象的大小被存储,但不是存储在每个对象中,而是在相应的类数据中只存储一次(因此类指针)。关于访问数组/对象中的数据,还有另一个区别:当访问数组的元素时,JVM必须进行边界检查,这需要知道数组的大小。然而,当访问普通对象的字段时,情况并非如此,因为所有字段的数量/位置都是固定的(并且在类加载时是已知的)。所以通常,知道一个对象的大小实际上并不需要访问它的数据。然而,我想把扫地机的评论相对化一下:JVM * 确实 * 需要知道非数组对象的大小,例如,当作为垃圾收集压缩的一部分移动它们时。
olqngx592#
JVM可以根据对象的类和对象字段在内存中的布局来确定对象的大小。创建对象时,JVM会为对象的标头(标记字和klass指针)及其字段分配内存。JVM使用对象的类来确定标头的大小以及字段的大小和类型。让我们考虑一个“Page”对象的数组,其中每个“Page”对象有两个字段,“text”和“images”。JVM将为数组头(标记字、klass指针和size头)和“Page”对象分配内存。标记字、klass指针和size头组成数组头,“Page”对象存储在头之后。当JVM需要读取数组中某个特定的“Page”对象的数据时,它从数组的起始地址开始,首先从数组头中读取标记字、klass指针和size头,size头包含数组大小的信息,JVM用它来确定数组中“Page”对象的个数。接下来,JVM使用klass指针来确定“Page”对象在内存中的布局。JVM知道每个“Page”对象的第一个字段是“text”字段,它是一个字符串,因此它读取必要的字节数来检索它感兴趣的特定“Page”对象的“text”字段的值。接下来,JVM知道下一个字段是“images”字段,它也是一个字符串,因此它读取必要的字节数来检索同一“Page”对象的“images”字段的值。通过使用klass指针来确定字段在内存中的布局,JVM能够高效准确地读取数组中特定“Page”对象的数据,即使数组包含大量“Page”对象,JVM每次需要访问数组中某个对象的数据时都会执行此过程,这使得它成为JVM内存管理系统的重要组成部分。
2条答案
按热度按时间dtcbnfnu1#
数组和“普通”对象的区别在于数组可以有不同的大小,而给定类的每个对象都有相同的大小。在某种程度上,非数组对象的大小被存储,但不是存储在每个对象中,而是在相应的类数据中只存储一次(因此类指针)。
关于访问数组/对象中的数据,还有另一个区别:当访问数组的元素时,JVM必须进行边界检查,这需要知道数组的大小。然而,当访问普通对象的字段时,情况并非如此,因为所有字段的数量/位置都是固定的(并且在类加载时是已知的)。所以通常,知道一个对象的大小实际上并不需要访问它的数据。然而,我想把扫地机的评论相对化一下:JVM * 确实 * 需要知道非数组对象的大小,例如,当作为垃圾收集压缩的一部分移动它们时。
olqngx592#
JVM可以根据对象的类和对象字段在内存中的布局来确定对象的大小。创建对象时,JVM会为对象的标头(标记字和klass指针)及其字段分配内存。JVM使用对象的类来确定标头的大小以及字段的大小和类型。
让我们考虑一个“Page”对象的数组,其中每个“Page”对象有两个字段,“text”和“images”。JVM将为数组头(标记字、klass指针和size头)和“Page”对象分配内存。标记字、klass指针和size头组成数组头,“Page”对象存储在头之后。
当JVM需要读取数组中某个特定的“Page”对象的数据时,它从数组的起始地址开始,首先从数组头中读取标记字、klass指针和size头,size头包含数组大小的信息,JVM用它来确定数组中“Page”对象的个数。
接下来,JVM使用klass指针来确定“Page”对象在内存中的布局。JVM知道每个“Page”对象的第一个字段是“text”字段,它是一个字符串,因此它读取必要的字节数来检索它感兴趣的特定“Page”对象的“text”字段的值。接下来,JVM知道下一个字段是“images”字段,它也是一个字符串,因此它读取必要的字节数来检索同一“Page”对象的“images”字段的值。
通过使用klass指针来确定字段在内存中的布局,JVM能够高效准确地读取数组中特定“Page”对象的数据,即使数组包含大量“Page”对象,JVM每次需要访问数组中某个对象的数据时都会执行此过程,这使得它成为JVM内存管理系统的重要组成部分。