Kullanarak "yeni" bir yapı üzerinde öbek üzerinde tahsis veya yığını mı?
new
operatörü ile bir sınıf örneği oluşturduğunuzda, bellek öbek üzerinde tahsis. new
operatörüyle bir yapı örneği oluşturduğunuzda bellek, yığın yığın veya ayrılmış mı ?
CEVAP
Not: C# 6 sana özel yazmak yapılar için parametresiz yapıcı. Bu cevap daha önce yazılmıştır, ve bu değişime ayak uydurabilmek için revize etmedim. (Yapıcı, diziler açısından, jenerik vb çağrıldığında açısından karışıktır.)
Tamam, eğer bunu daha açık bir şekilde ifade edebilir miyim, bir bakayım.
Öncelikle, Ash haklı: sorudeğilhakkında nerede değer yazındeğişkenlerayrılan bellek. Farklı bir soru ve cevap değil sadece bir "yığın". Bu (ve daha da karmaşık C# 2) daha karmaşık. article on the topic bir ben var ve istenirse üzerine genişleyecektir, ama new
operatörü ile baş başa bırak.
İkinci olarak, tüm bu gerçekten ne hakkında konuştuğunu bağlıdır. Derleyici şartlarda IL oluşturur kaynak kodu ile bakıyorum. JİT derleyici oldukça çok "" ayırma. mantıksal optimize uzakta açısından akıllıca şeyler yapmak mümkün.
Üçüncü olarak, çoğunlukla aslında kısmen şeyler çok karmaşık çünkü cevabı bilmiyorum çünkü jenerik görmezden geldim.
Son olarak, bütün bunlar geçerli uygulama ile. # Spec C bu pek belirtmeyen bir şekilde uygulanması bir ayrıntı. Yönetilen kod geliştiricilerin çok dikkat gerektiğini düşünenler var. O kadar uzağa gitmek istiyorum emin değilim, ama aslında tüm yerel değişkenler hala spec ile uyumlu olan yığınının üzerinde yaşadığı bir dünya hayal etmeye değer.
Değer türleri üzerindenew
operatörü ile iki farklı durum vardır: ya parametresiz bir kurucu (*9 örneğin*) veya parameterful yapıcı (*10 örneğin*) diyebilirsiniz. Bu önemli ölçüde farklı IL oluşturmak. C karşılaştırmak gerek anlamak için# ve CLİ özellikleri: göre C#, tüm değer türleri parametresiz bir kurucu var. CLİ spec görehayırdeğer türleri parametresiz kurucular var. (Yansıma ile bir değer türü bir süre kurucular - bir parametresiz bir bulamazlar getir.)
C mantıklıdır# "sıfır ile bir değeri dilini tutar için" yapıcı, tutarlı - new(...)
olarak düşünebilirsiniz . başlatma tedavisinde ^em>her zamanbir kurucu çağırmak. SİSTEMİNDE onu aramak için gerçek kod yok Hayır olarak farklı, ve kesinlikle yazın - özel kod düşünmek için mantıklı.
Ayrıca başlatıldı sonra değeri ile yapmak için gidiyoruz ne bir fark yapar. IL için kullanılır
Guid localVariable = new Guid(someString);
IL için farklı kullanılır:
myInstanceOrStaticVariable = new Guid(someString);
Eğer değer Ara değer olarak kullanılır ayrıca, eğer, örneğin, bir yöntem çağrısı için bir argüman, işler biraz farklı. Tüm bu farklılıkları göstermek için, burada kısa bir test programı. IL stfld
stsfld
arasındaki farkı olur ama hepsi bu. statik değişkenler ve örnek değişkenleri arasında fark görünmüyor:
using System;
public class Test
{
static Guid field;
static void Main() {}
static void MethodTakingGuid(Guid guid) {}
static void ParameterisedCtorAssignToField()
{
field = new Guid("");
}
static void ParameterisedCtorAssignToLocal()
{
Guid local = new Guid("");
// Force the value to be used
local.ToString();
}
static void ParameterisedCtorCallMethod()
{
MethodTakingGuid(new Guid(""));
}
static void ParameterlessCtorAssignToField()
{
field = new Guid();
}
static void ParameterlessCtorAssignToLocal()
{
Guid local = new Guid();
// Force the value to be used
local.ToString();
}
static void ParameterlessCtorCallMethod()
{
MethodTakingGuid(new Guid());
}
}
İşte bu sınıf, alakasız bit hariç, IL (nops):
.class public auto ansi beforefieldinit Test extends [mscorlib]System.Object
{
// Removed Test's constructor, Main, and MethodTakingGuid.
.method private hidebysig static void ParameterisedCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: stsfld valuetype [mscorlib]System.Guid Test::field
L_0010: ret
}
.method private hidebysig static void ParameterisedCtorAssignToLocal() cil managed
{
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: ldstr ""
L_0008: call instance void [mscorlib]System.Guid::.ctor(string)
// Removed ToString() call
L_001c: ret
}
.method private hidebysig static void ParameterisedCtorCallMethod() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0011: ret
}
.method private hidebysig static void ParameterlessCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldsflda valuetype [mscorlib]System.Guid Test::field
L_0006: initobj [mscorlib]System.Guid
L_000c: ret
}
.method private hidebysig static void ParameterlessCtorAssignToLocal() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
// Removed ToString() call
L_0017: ret
}
.method private hidebysig static void ParameterlessCtorCallMethod() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
L_0009: ldloc.0
L_000a: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0010: ret
}
.field private static valuetype [mscorlib]System.Guid field
}
Gördüğünüz gibi, farklı talimatları kurucu çağırmak için kullanılan bir sürü vardır:
newobj
: Bu değer, arama parametrik yapıcı yığını Ayırır. Ara değerler için, örneğin, bir alan için atama için kullanılan yöntem ya da bir değişken olarak kullanın.call instance
: Kullanır zaten ayrılmış bir depolama konumu yığını olsun ya da olmasın (). Bu yerel bir değişken atamak için yukarıdaki kod içinde kullanılır. Eğer aynı yerel değişken değeri birkaç keznew
birkaç çağrılarını kullanarak atanırsa, sadece eski değeri - üstüne verilerini başlatıryokdaha fazla alan her zaman yığın ayırma.initobj
: zaten ayrılmış bir depolama konumu ve mendil sadece veri Kullanır. Bu tüm parametresiz yapıcı konuşmaları, yerel bir değişkene Atamak da dahil için kullanılır. Yöntem çağrısı için, Ara yerel bir değişken etkili bir şekilde tanıtıldı ve değeriinitobj
sildi.
Bu ne kadar karmaşık bir konu aynı zamanda ışık biraz parlak olsa, gösterir umarım.bazıkavramsal duyular, 23 ** Her çağrı yığını üzerinde yer ayırıyor ama gördüğümüz gibi, bu gerçekten de IL düzeyinde olacak şey değil. Özel bir durum belirtmek istiyorum. Bu yöntem:
void HowManyStackAllocations()
{
Guid guid = new Guid();
// [...] Use guid
guid = new Guid(someBytes);
// [...] Use guid
guid = new Guid(someString);
// [...] Use guid
}
Bu "mantıklı" 4 yığın ayırma için bir tane daha değişken ve her biri için üç new
telefon ama aslında (açık kod) yığın yalnızca bir kez ayrılan ve daha sonra aynı depolama konumu yeniden.
EDİT: Sadece açık olmasını, bu tek gerçek bazı durumlarda... özellikle değeri guid
olmayacak görünüyorsa Guid
yapıcı bir istisna atar, bu yüzden C# derleyicisi dahil olmak üzere yeniden aynı yığın yuvası. Nereye Lippert blog post on value type construction Eric daha fazla bilgi ve bir dava için bkzyokuygulayın.
Bu cevabı yazmak çok - lütfen eğer herhangi belli değil açıklama isteyin öğrendim!
Yeni "kullanın HTML5 semantik biç...
Eclipse "bu derleme birimi java p...
&; 'Access-Control-Allow-Origin&#...
Nasıl değişmez bir " baskı miyim;{}&qu...
&Quot;Bir girişim, yanlış bir biçimde ...