Java 静态方法的内存模型
Java memory model for static methods
我来自操作系统和 C 语言背景,编译代码时世界很简单。需要处理和理解堆栈、堆文本部分等
当我开始学习 Java(我知道 JVM 和垃圾收集器)时,我被静态方法逗乐了。根据我的理解,class 的所有实例都会在堆中创建,然后进行清理。但是,对于静态方法,您不需要 class 的实例。
所以,有人可以解释一下非静态方法和静态方法在内存模型上有何不同。它们是否都驻留在内存的文本部分。或者我完全把事情搞砸了。
谢谢
在 Java 中,classes 的字节码(包括它们的静态方法和实例方法)是堆的一部分(通常在特殊的 "permanent generation" 部分中对于长寿命的对象)。
类 也可以被垃圾收集,但这通常不会发生很多(仅当 class 从非系统 classloader 加载并且整个class加载程序已过时,例如在卸载 Web 应用程序时)。
However, for a static method, you don't need an instance of the class.
没错。但是所有方法都是 class 定义的一部分,并在加载 class 时一起加载。即使你从来没有创建一个class的实例,所有实例方法的代码都会被加载到堆内存中。
然后是本地代码的 JIT 编译:使用 Hotspot,常用方法的字节码被进一步编译为本地机器代码。其结果确实会进入堆之外的某个地方进入本机内存,并且只会发生在实际使用的方法(静态或非静态)上。
您的理解是 class 的所有 实例 都在堆中创建...
不完全正确,所有 classes 都被编译成对象字节码,否则 JVM 无法执行。实例和静态方法都生成相同的对象字节码。即使是非静态 classes 也只生成其对象字节码的单一版本。所有实例 classes 都有自己的指针,指向它们在单个字节代码副本中的执行位置。真正的区别在于 class 的数据成员。非静态 class 的每个实例都必须拥有自己的所有非静态数据成员(变量)副本,但是静态数据成员在内存中只有一个副本,因为 [=20] 的静态数据成员=] 由 class 静态或非静态的所有实例共享。
静态 class 或非静态 class 的静态数据成员在内存中都有自己的一个副本。
非静态 class 在内存中仍然只有其目标代码的一个副本,只有非静态数据会为每个实例在内存中获取一个副本。
我来自操作系统和 C 语言背景,编译代码时世界很简单。需要处理和理解堆栈、堆文本部分等
当我开始学习 Java(我知道 JVM 和垃圾收集器)时,我被静态方法逗乐了。根据我的理解,class 的所有实例都会在堆中创建,然后进行清理。但是,对于静态方法,您不需要 class 的实例。
所以,有人可以解释一下非静态方法和静态方法在内存模型上有何不同。它们是否都驻留在内存的文本部分。或者我完全把事情搞砸了。
谢谢
在 Java 中,classes 的字节码(包括它们的静态方法和实例方法)是堆的一部分(通常在特殊的 "permanent generation" 部分中对于长寿命的对象)。
类 也可以被垃圾收集,但这通常不会发生很多(仅当 class 从非系统 classloader 加载并且整个class加载程序已过时,例如在卸载 Web 应用程序时)。
However, for a static method, you don't need an instance of the class.
没错。但是所有方法都是 class 定义的一部分,并在加载 class 时一起加载。即使你从来没有创建一个class的实例,所有实例方法的代码都会被加载到堆内存中。
然后是本地代码的 JIT 编译:使用 Hotspot,常用方法的字节码被进一步编译为本地机器代码。其结果确实会进入堆之外的某个地方进入本机内存,并且只会发生在实际使用的方法(静态或非静态)上。
您的理解是 class 的所有 实例 都在堆中创建...
不完全正确,所有 classes 都被编译成对象字节码,否则 JVM 无法执行。实例和静态方法都生成相同的对象字节码。即使是非静态 classes 也只生成其对象字节码的单一版本。所有实例 classes 都有自己的指针,指向它们在单个字节代码副本中的执行位置。真正的区别在于 class 的数据成员。非静态 class 的每个实例都必须拥有自己的所有非静态数据成员(变量)副本,但是静态数据成员在内存中只有一个副本,因为 [=20] 的静态数据成员=] 由 class 静态或非静态的所有实例共享。
静态 class 或非静态 class 的静态数据成员在内存中都有自己的一个副本。
非静态 class 在内存中仍然只有其目标代码的一个副本,只有非静态数据会为每个实例在内存中获取一个副本。