简体   繁体   English

Java中存储的内存地址在哪里

[英]Where are memory addresses stored in Java

Where are memory address stored in Java ? Java中的内存地址存储在哪里? What I am trying to understand is how something like the following is stored. 我想要了解的是如何存储以下内容。 I already know the difference between stack and heap but trying to dig a layer deeper than that. 我已经知道堆栈和堆之间的区别,但尝试深入研究。

int i = 5;

Is i stored separately and 5 stored separately, and then a mapping is established? i是分开存放,还是5分开存放,然后建立映射?

Similarly, we say that for a 32 bit version one can have at most 4 GB RAM (much less in reality), where are the memory addresses of all these memory blocks are stored ? 类似地,我们说对于32位版本,最多可以有4 GB RAM(实际上要少得多),所有这些内存块的内存地址都存储在哪里?

What I am trying to understand is how something like the following is stored. 我想要了解的是如何存储以下内容。

It depends on where that int i = 5; 这取决于int i = 5; is: 是:

Local Variable 局部变量

If that's within a method and therefore i is a local variable, then 5 is stored as a local on the stack ( i isn't "stored" anywhere, the bytecode generator just remembers where on the stack i is). 如果那是在一个方法中,因此i是一个局部变量,那么5被存储为堆栈中的本地( i没有“存储”在任何地方,字节码生成器只记得i在堆栈上的位置)。 Bytecode has specific instructions for interacting with local variables, including some quite efficient dedicated no-args versions, such as iload_0 which loads an int from "local variable 0". 字节码具有与局部变量交互的特定指令,包括一些非常有效的专用无参数版本,例如iload_0 ,它从“局部变量0”加载一个int (Those go through iload_3 , and then there's a version taking an arg, iload followed by an index.) (那些经过iload_3 ,然后有一个版本服用精氨酸, iload其次为指数。)

Consider this class: 考虑这个课程:

public class Example {

    public static final void main(String[] args) {
        int i = 5;

        System.out.println(i);
    }
}

Here's the bytecode for that (you can get this by compiling it and then doing javap -c Example ), with notes to the right: 这是字节码(你可以通过编译然后执行javap -c Example来获得这个),右边有注释:

public class Example {
  // ...omitted constructor stuff...

  public static final void main(java.lang.String[]);
    Code:
      // The `int i = 5;` line:
       0: iconst_5               // Load the constant 5 onto the stack
       1: istore_1               // Store it in local variable 1

      // The `System.out.println(i);` line:
       2: getstatic     #2       // Get the static field java/lang/System.out:Ljava/io/PrintStream onto the stack
       5: iload_1                // Load int variable 1 on the stack
       6: invokevirtual #3       // Call java/io/PrintStream.println, which gets
                                 // the stream and what to write from the stack
       9: return
}

Note the two different uses of the stack there: The "locals" are on the part of the stack that the method allocated itself for locals (since it knows in advance how many there are), and then there's the dynamic part following that that it uses for passing information into methods and such. 请注意堆栈的两种不同用途:“locals”位于堆栈的一部分,该方法为本地分配了自己(因为它事先知道有多少),然后是动态部分,然后是它用于将信息传递到方法等中。

Instance field 实例字段

If that's within a class definition and therefore i is an instance field of the class, i is part of the structure that Java reserves (either on the stack or heap, sometimes moving between them) for the instance. 如果那是在类定义中,因此i是类的实例字段,那么i就是Java为实例保留的结构的一部分(在堆栈或堆上,有时在它们之间移动)。

Bytecode doesn't really shed a lot of light on this, but consider this class: 字节码并没有真正摆脱了很多这种光的,但考虑到这个类:

public class Example {

    int i = 5;

    public static final void main(String[] args) {

        Example ex = new Example();
        System.out.println(ex.i);
    }
}

Here's the bytecode for that: 这是字节码:

public class Example {
  // Here's the instance field
  int i;

  // ...omitted the constructor stuff...

  public static final void main(java.lang.String[]);
    Code:
      // Create our Example instance and save it in a local variable
       0: new           #3
       3: dup
       4: invokespecial #4
       7: astore_1

      // The `System.out.println(ex.i)` line:
       8: getstatic     #5     // Get the java/lang/System.out:Ljava/io/PrintStream field
      11: aload_1              // Get `ex` onto the stack
      12: getfield      #2     // Get the value of field `i` onto the stack from the instance we just put on the stack (pops the instance off)
      15: invokevirtual #6     // Call java/io/PrintStream.println, which
                               // again gets the stream to write to and
                               // what to write from the stack
      18: return
}

Where are memory address stored in Java ? Java中的内存地址存储在哪里?

In Java references are not just memory addresses and due to compressed oops, they are used very rarely for Java related data. 在Java中,引用不仅仅是内存地址,而且由于压缩的oop,它们很少用于与Java相关的数据。

What I am trying to understand is how something like the following is stored. 我想要了解的是如何存储以下内容。

It is worth remembering that the JVM is a virtual machine, you can say how it is notionally stored in byte code but the code itself goes through multiple stages of optimisation and it could change each time. 值得记住的是,JVM是一个虚拟机,您可以说它是如何在字节代码中以理论方式存储的,但代码本身经历了多个优化阶段,并且每次都可以更改。

Also the JVM is very good at optimising away code which doesn't do anything so in many trivial cases the answer is; 此外,JVM非常擅长优化代码,这些代码在许多琐碎的情况下都没有做任何事情。 nowhere, the code has been inlined away to nothing. 没有任何地方,代码已被内联到任何东西。

I already know the difference between stack and heap but trying to dig a layer deeper than that. 我已经知道堆栈和堆之间的区别,但尝试深入研究。

 int i = 5;

Is i stored separately and 5 stored separately, and then a mapping is established? 我是单独存储还是单独存储,然后建立映射?

At runtime, it is a good chance the value has been inlined out of existence. 在运行时,很有可能内联的值已经存在。 However, it could be on the stack, the heap or both depending on the context. 但是,它可能位于堆栈,堆或两者上,具体取决于上下文。

Similarly, we say that for a 32 bit version one can have at most 4 GB RAM (much less in reality), where are the memory addresses of all these memory blocks are stored ? 类似地,我们说对于32位版本,最多可以有4 GB RAM(实际上要少得多),所有这些内存块的内存地址都存储在哪里?

In the 32-bit version you can only use the largest continuous region available as the heap. 在32位版本中,您只能使用最大的连续区域作为堆。 This is limited to about 1.4 GB on windows and about 3 GB on Unix. 这限制在Windows上大约1.4 GB和Unix上大约3 GB。

In the 64-it version, it generally uses 32-bit references which go through a translation to allow you to address up to 32 GB (Java 7) and 64 GB (Java 8) Without Compressed Oops you can address a 48-bit address space on most OSes (limited by the hardware and OS) 在64-it版本中,它通常使用32位引用,通过转换允许您处理最多32 GB(Java 7)和64 GB(Java 8)而不使用Compressed Oops您可以寻址48位地址大多数操作系统上的空间(受硬件和操作系统限制)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM