java 静态字段在内部究竟是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14781993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How exactly do static fields work internally?
提问by Koray Tugay
Say you have a class,
说你有一堂课,
class Foo
{
public static bar;
}
When you say:
当你说:
new Foo();
I can imagine that in memory, a space is reserved for this object.
我可以想象,在内存中,为这个对象保留了一个空间。
...and when you say again:
......当你再次说:
new Foo();
...well now you have another space available for the object.
...好吧,现在您有另一个空间可用于该对象。
However, where exactly does the static field live?
然而,静态字段究竟存在于何处?
What I am really trying to learn is:
我真正想学习的是:
How do the references to the objects reference the same field of the objects they reference?
对对象的引用如何引用它们引用的对象的相同字段?
回答by Daniel A.A. Pelsmaeker
While the exact details of the type system are implementation dependent, let me go into some more detail than just stating that it dependsand you should not care. I'll describe how it approximately works in Microsoft's implementation (.NET) according to the book CLR via C#by Jeffrey Richterand the article See How the CLR Creates Runtime Objectsby Hanu Kommalapati et al.(original MSDN May 2005 issue).
虽然类型系统的具体细节依赖于实现,让我去到一些更详细的不仅仅是指出,这取决于和你不应该在乎。我将根据Jeffrey Richter 的CLR via C#一书和Hanu Kommalapati 等人的文章See How the CLR Creates Runtime Objects描述它如何在 Microsoft 的实现 (.NET) 中大致工作。(原始 MSDN 2005 年 5 月发行)。
Say you have a class:
假设你有一个类:
class Foo
{
// Instance fields
string myBar = "Foobar";
int myNum;
// Static fields
static string bar = "Foobar";
static int num;
}
Foo myFoo = new Foo();
Type typeOfFoo = typeof(Foo);
Where do the instance fields live?
实例字段在哪里?
Whenever you say new Foo()
, space is allocated and initialized for the object instance, and the constructor is called. This instance is shown as instance of Fooin the image below. Such as instance contains only the instance fields of the class (in this case myBar
and myNum
), and for objects allocated on the heap two extra fields used by the runtime (Sync block index
and Type handle
). The type handle is a pointer to a Type
object that describes the type of the instance, in this case type of Foo.
每当您说 时new Foo()
,都会为对象实例分配和初始化空间,并调用构造函数。此实例在下图中显示为Foo 的实例。例如 instance 仅包含类的实例字段(在本例中为myBar
和myNum
),并且对于在堆上分配的对象,运行时使用的两个额外字段(Sync block index
和Type handle
)。类型句柄是一个指向Type
描述实例类型的对象的指针,在本例中为 Foo 类型。
When you say new Foo()
again, new space is allocated which will again contain space for the instance fields of the type. As you can see, instance fields are associated with object instances.
当您new Foo()
再次说时,将分配新空间,其中将再次包含该类型的实例字段的空间。如您所见,实例字段与对象实例相关联。
The runtime puts each instance field at a fixed offset from the start of the object's data. For example, myBar
might live at offset +4. The address of the instance field is simply the address of the object plus the offset of the field.
运行时将每个实例字段放置在距对象数据开头的固定偏移量处。例如,myBar
可能居住在偏移量 +4。实例字段的地址只是对象的地址加上字段的偏移量。
Where do the static fields live?
静态字段在哪里?
Static fields in C# and Java are not associated with any object instance, but with a type. Classes, structs and enums are examples of types. Only once (per type) is some space allocated to hold the values of the static fields. It would make sense to allocate space for the static fields in the Type
structure that describes the type, since there is also only one Type
object per type. This is the approach taken by C# and Java.
C# 和 Java 中的静态字段不与任何对象实例相关联,而是与类型相关联。类、结构和枚举是类型的示例。只有一次(每种类型)分配了一些空间来保存静态字段的值。为Type
描述类型的结构中的静态字段分配空间是有意义的,因为Type
每种类型也只有一个对象。这是 C# 和 Java 所采用的方法。
The Type
object1is created when the type is loaded by the runtime. This structure contains all sorts of information needed for the runtime to be able to allocate new instances, call methods and perform casting, among other things. It also contains the space for the static fields, in this case bar
and num
.
在Type
对象1时的类型由运行时加载的被创建。该结构包含运行时能够分配新实例、调用方法和执行转换等所需的各种信息。它还包含用于静态字段的空间,在本例中为bar
和num
。
The runtime has put each static field at some offset from the start of the type's data. This is different for each type. For example, bar
might live at offset +64. The address of the static field is the address of the Type
object plus the offset of the field. The type is statically known.
运行时已将每个静态字段放置在距类型数据开头的某个偏移处。这对于每种类型都是不同的。例如,bar
可能位于偏移量 +64。静态字段的地址是Type
对象的地址加上字段的偏移量。类型是静态已知的。
1) In Microsoft .NET multiple different structures describe a type, such as the MethodTableand the EEClassstructures.
1) 在 Microsoft .NET 中,多个不同的结构描述了一个类型,例如MethodTable和EEClass结构。
回答by Reed Copsey
This completely depends on the implementation in question. For C# and Java, the runtime is allowed to determine where to store the memory for the variable. For C and most compiled languages, the compiler makes this determination.
这完全取决于所讨论的实现。对于 C# 和 Java,允许运行时确定存储变量内存的位置。对于 C 语言和大多数编译语言,编译器会做出此决定。
That being said, in practice, it doesn't matter. The usage it determined by specification, so you are free to use the variable knowing the behavior will be guaranteed.
话虽如此,在实践中,这并不重要。它的用法由规范决定,因此您可以自由使用该变量,知道行为将得到保证。
回答by assylias
For Java, objects referred to by static fields will reside on the heaplike other objects:
对于 Java,静态字段引用的对象将像其他对象一样驻留在堆中:
The heap is the runtime data area from which memory for all class instances and arrays is allocated.
堆是运行时数据区,从中分配所有类实例和数组的内存。
The field will be initialised (if the declaration contains an initialization) when the class is loaded, which happens immediately before the first occurrence of any one of the following:
该字段将在加载类时初始化(如果声明包含初始化),这会在以下任何一项第一次出现之前立即发生:
- an instance of the class is created.
- a static method declared by the class is invoked.
- a static field declared by the class is assigned.
- a static field declared by the class is used and the field is not a constant variable (§4.12.4).
- 类的一个实例被创建。
- 调用类声明的静态方法。
- 分配了类声明的静态字段。
- 使用类声明的静态字段,该字段不是常量变量(第 4.12.4 节)。
The access to the static field is done via 2 special JVM instructions, getstaticand putstatic. But apart from that distinction, static fields are similar to non static fields.
对静态字段的访问是通过 2 个特殊的 JVM 指令完成的,getstatic和putstatic。但除此之外,静态字段与非静态字段类似。
回答by JerKimball
This varies wildly from language to language, and can even vary wildly from platform to platform...
这因语言而异,甚至可能因平台而异......
For example, on the .NET side, static members are "associated" with the governing EEClass
definition, which canbe a heap-allocated ORa "wherever" allocated member (the C# spec doesn't specify heap/stack behavior, it's an implementation detail of the VM)
例如,在 .NET 方面,静态成员与管理EEClass
定义“关联” ,它可以是堆分配的或“任何地方”分配的成员(C# 规范没有指定堆/堆栈行为,它是一个实现VM 的详细信息)
回答by Olivier Jacot-Descombes
There might be exceptions, but for reference types the new
-keyword usually creates an object in an internal data structure called "heap". The heap is managed by the CLR (Common Language Runtime). It makes no difference whether you have a static or instance member or a local variable.
可能有例外,但对于引用类型,new
-keyword 通常会在称为“堆”的内部数据结构中创建一个对象。堆由 CLR(公共语言运行时)管理。无论您拥有静态成员、实例成员还是局部变量,都没有区别。
The difference between static members and instance members (the ones without the keyword static
) is, that static members exist only once per type (class, struct) and instance members exist once per instance (per object).
静态成员和实例成员(没有关键字的那些static
)之间的区别在于,静态成员每个类型(类、结构)只存在一次,实例成员每个实例(每个对象)只存在一次。
It is only the reference which is static or not; this distinction does not apply to the referenced object (unless the object is a value type). A static member, an instance member and a local variable can all reference the same object.
只有引用是静态的还是非静态的;这种区别不适用于被引用的对象(除非该对象是值类型)。静态成员、实例成员和局部变量都可以引用同一个对象。
回答by Jens Kloster
Im only familiar with C#, and this is my understanding of it:
我只熟悉 C#,这是我对它的理解:
Then your program starts, it loads all the related assemblies into an AppDomain. When the assambly is loaded, all static constructors are called, including static fields. They will live in the there, and the only way to unload them, is to unload the AppDomain.
然后您的程序启动,它将所有相关程序集加载到 AppDomain 中。加载组装时,将调用所有静态构造函数,包括静态字段。它们将住在那里,卸载它们的唯一方法是卸载 AppDomain。
回答by Can Geli?
Static variables belong to the class not the object so there is only one bar
in the memory even if you initialize thousands of instants of Foo
.
静态变量属于类而不是对象,因此bar
即使您初始化了数千个Foo
.
回答by Ashish Gupta
Static members and constants are stored on heap. Unlike objects on heap that can get garbage collection, Static members and constants do stay till Appdomain is torn down, Hence once should be carefull in dealing with static fields
静态成员和常量存储在堆上。与堆上的对象可以进行垃圾回收不同,静态成员和常量确实会一直存在,直到 Appdomain 被拆除,因此在处理静态字段时应该小心
回答by Jatin Khurana
This depends on the language to language or the designer of the language. If I talk about Java, static members store in the Method area of the JVM and all the object are linked to them. One more thing that is very important to know is that we can access the static data member without creating the object of the class.It means the allocation of the memory to the static data members doesn't depend on the creation of the object of that class.
这取决于语言到语言或语言的设计者。如果我谈论 Java,静态成员存储在 JVM 的 Method 区域中,并且所有对象都链接到它们。还有一件非常重要的事情是,我们可以在不创建类的对象的情况下访问静态数据成员。这意味着静态数据成员的内存分配不依赖于该类的对象的创建班级。
回答by Mikhail
By specification static variables are stored in Constant Pool. JVM stores this info in Permanent Generation.
按照规范,静态变量存储在Constant Pool 中。JVM 将此信息存储在永久代中。