这个问题已经在这里有一个答案:
- Java的:在哪里静态字段生活记忆中? 5个回答
假设你有一个类,
class Foo
{
public static bar;
}
当你说:
new Foo();
我可以想像,在内存中,一个空间保留给该对象。
...当你再次说:
new Foo();
......那么现在你有可用于该对象的另一个空间。
然而,正是它的静态字段住?
我真的很努力学习的是:
如何对对象的引用引用所引用的对象的同场?
这个问题已经在这里有一个答案:
假设你有一个类,
class Foo
{
public static bar;
}
当你说:
new Foo();
我可以想像,在内存中,一个空间保留给该对象。
...当你再次说:
new Foo();
......那么现在你有可用于该对象的另一个空间。
然而,正是它的静态字段住?
我真的很努力学习的是:
如何对对象的引用引用所引用的对象的同场?
虽然类型系统的具体细节依赖于实现,让我去到一些更详细的不仅仅是指出, 这取决于 你不应该关心 。 我按照书上介绍它如何大约在微软的实现(.NET)的作品由杰弗里里希特通过C#CLR和文章,请参阅CLR如何创建由Hanu Kommalapati等运行时对象 。 ( 原2005 MSDN月发行 )。
假设你有一个类:
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);
你在哪里的实例字段住?
无论何时说new Foo()
空间分配和对象实例初始化,构造函数被调用。 这种情况下被示出为下面的图像中的Foo的实例 。 如实例仅包含类(在此情况下的实例字段myBar
和myNum
),以及用于在由运行时(使用的堆两个附加字段分配的对象Sync block index
和Type handle
)。 类型手柄是一个指针,指向Type
描述实例的类型,在这种情况下Foo类型的对象。
当你说new Foo()
再次,新的空间分配,这将再次含有空间类型的实例字段。 正如你所看到的,实例字段与对象实例相关联。
运行时使每个实例字段在从该对象的数据的开始的固定偏移。 例如, myBar
可能住在偏移+4。 实例字段的地址仅仅是对象的地址加场的偏移量。
你在哪里的静态字段住?
在C#和Java的静态字段不与任何对象实例关联,但有一个类型。 类,结构和枚举都是类型的例子。 只有一次(每类)分配给持有静态字段的值一定的空间。 这将是有意义的在静态字段分配空间Type
描述式结构,因为也有只有一个Type
每个类型的对象。 这是C#和Java所采取的做法。
的Type
,当类型是由运行时加载对象被创建1。 该结构包含所需运行时的各种信息,能够分配新实例,调用方法并进行铸造,等等。 它还包含了静态字段的空间,在这种情况下, bar
和num
。
运行时已经把每个静态字段一些从类型的数据的起始位置的偏移。 这是针对每种类型的不同。 例如, bar
可能住在偏移+64。 静态字段的地址是地址Type
对象加场的偏移量。 类型是静态已知的。
1)在的Microsoft .NET多个不同的结构描述一种类型,如方法表和EEClass结构。
这完全取决于相关的实施。 对于C#和Java运行时被允许确定在哪里存储该变量的存储器。 对于C和大多数编译语言,编译器做出此确定。
话虽这么说,但实际上, 它并不重要 。 使用它的规格决定,所以你可以自由使用变量明知的行为将得到保证。
这从语言变化很大,以语言,甚至可以从平台上变化很大,以平台...
例如,在.NET侧,静态成员“关联”以理事EEClass
定义,其可以是堆分配或 “哪里”分配部件(C#规范没有指定堆/堆栈行为,这是一个虚拟机的实现细节)
对于Java,对象提到了静态字段将驻留在堆上像其他对象:
堆是从哪个存储器的所有类实例和数组分配运行时数据区。
的字段将被初始化(如果该声明包含初始化)时的类被装载 ,其中以下中的任一个的第一次出现之前立即发生:
- 一个类的实例被创建。
- 由类声明的静态方法被调用。
- 在类中声明静态字段分配。
- 由类声明的静态域的使用量和字段不是常量变量(§4.12.4)。
对静态字段的访问是通过2个特别JVM指令,完成getstatic和putstatic 。 但是,除了这个区别,静态字段类似于非静态字段。
可能有例外,但对于引用类型的new
-keyword通常被称为“堆”的内部数据结构创建一个对象。 堆是由CLR(公共语言运行库)管理。 这都没有区别你是否有一个静态或实例成员或局部变量。
(没有关键字的那些静态成员和实例成员之间的差异static
)是,静态成员每类型只有一次存在(类,结构)和实例成员每个实例存在一次(每个对象)。
只有这是静态的或不是基准; 这种区别并不适用于被引用的对象(除非对象是一个值类型)。 静态成员,一个实例成员和一个局部变量可以全部引用相同的对象。
我只是熟悉C#,这是我对它的理解:
那么你的程序启动时,它加载所有相关组件到一个AppDomain。 当assambly被加载,所有静态构造函数的调用,包括静态字段。 他们将生活在那里,并卸载它们的唯一途径,就是要卸载的AppDomain。
静态成员和常数存储在堆。 不同于上堆物,可以让垃圾收集,静态成员和常量就留到AppDomain中被拆除,因此一旦应该在处理静态字段要小心
静态变量属于类而不是对象所以只有一个bar
,即使你初始化成千上万的瞬间的记忆Foo
。
这取决于语言对语言或语言的设计者。 如果我讲的Java,静态成员在JVM中所有对象的方法区域存储链接到这些。 还有一个就是要知道很重要的事情是,我们可以访问静态数据成员,而无需创建class.It的对象是指内存的静态数据成员的分配不依赖于创建该对象的类。
通过规范的静态变量存储在常量池 。 JVM存储这个信息在永久代。
通常的静态变量被存储在程序存储器的数据段。 所以对于创建的每个类/是正在运行的程序将创建一个数据段的静态变量和所有其它变量在代码段初始化。
所以基本上它像
+++++++++++++++++++++++++++++++++++++
+ DATA Segment
+ -static vars
+
+----------------------------------
+ instances | instances | instances|
+ | | |
这里单区域实例之间共享。
从维基百科 “的数据区域包含由是程序中使用全局和静态变量
明确初始化值“。