Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Önemli
Bu bölümde açıklanan teknikler, kodunuzdaki sık erişimli yollara uygulandığında performansı artırır. Sıkça kullanılan yollar, kod tabanınızın normal işlemler sırasında sık ve sürekli olarak yürütülen bölümleridir. Bu tekniklerin genellikle yürütülmeyen kodlara uygulanması en az etkiye sahip olacaktır. Performansı geliştirmek için herhangi bir değişiklik yapmadan önce temeli ölçmek kritik önem taşır. Ardından, bellek performans sorunlarının nerede oluştuğunu belirlemek için bu temeli analiz edin. Tanılama ve izleme bölümünde uygulamanızın performansını ölçmek için birçok platformlar arası araç hakkında bilgi edinebilirsiniz. Visual Studio belgelerinde bellek kullanımını ölçme öğreticisinde profil oluşturma oturumu uygulayabilirsiniz.
Bellek kullanımını ölçtükten ve ayırmaları azaltabileceğinizi belirledikten sonra, ayırmaları azaltmak için bu bölümdeki teknikleri kullanın. Ardışık her değişiklik sonrasında bellek kullanımını yeniden ölçün. Her değişikliğin uygulamanızdaki bellek kullanımı üzerinde olumlu bir etkisi olduğundan emin olun.
.NET'te performans çalışması genellikle kodunuzdan ayırmaların kaldırılması anlamına gelir. Ayırdığınız her bellek bloğunun sonunda serbest olması gerekir. Daha az ayırma, çöp toplamada harcanan süreyi azaltır. Belirli kod yollarından çöp koleksiyonlarını kaldırarak daha öngörülebilir yürütme süresi sağlar.
Ayırımları azaltmak için yaygın bir taktik, kritik veri yapılarını class türlerinden struct türlerine değiştirmektir. Bu değişiklik, bu türlerin kullanılmasının semantiğini etkiler. Parametreler ve dönüşler artık başvuru yerine değere göre geçirilir. Bir değeri kopyalamanın maliyeti, türler küçük, üç sözcük veya daha azsa (bir sözcüğün bir tamsayının doğal boyutunda olduğu düşünüldüğünde) göz ardı edilebilir. Ölçülebilir ve daha büyük türler için gerçek performans etkisine sahip olabilir. Kopyalamanın etkisiyle mücadele etmek için, geliştiriciler bu türleri ref ile geçirerek hedeflenen semantiği geri alabilirler.
C# ref özellikleri, genel kullanılabilirliklerini olumsuz etkilemeden türler için struct istenen semantiği ifade edebilmenizi sağlar. Bu geliştirmelerden önce geliştiricilerin aynı performans etkisini elde etmek için unsafe işaretçiler ve ham bellek ile yapılara başvurması gerekiyordu. Derleyici, yeni ilgili özellikler için ref oluşturur.
Doğrulanabilir güvenli kod, derleyicinin olası arabellek taşmalarını veya ayrılmamış ya da serbest bırakılmış belleğe erişmeyi algılaması anlamına gelir. Derleyici bazı hataları algılar ve engeller.
Referans yoluyla geçirme ve döndürme
C# içindeki değişkenler değerleri depolar. Türlerde struct değer, türün bir örneğinin içeriğidir. Türlerde class değer, türün bir örneğini depolayan bir bellek bloğuna başvurudur. Değiştiricinin ref eklenmesi, değişkenin değere başvuruyu depoladığını gösterir.
struct türlerinde, referans değeri içeren depolamaya işaret eder.
class türlerinde, başvuru, bellek bloğuna olan başvuruyu içeren depolamaya işaret eder.
C# dilinde, yöntemlere yönelik parametreler değere göre geçirilir ve dönüş değerleri değere göre döndürülür. Bağımsız değişkeninin değeri yönteme geçirilir. Dönüş bağımsız değişkeninin değeri , dönüş değeridir.
ref, in, ref readonlyveya out değiştiricisi, bağımsız değişkenin başvuruyla geçirildiğini gösterir. Depolama konumuna bir başvuru yönteme geçirilir. Yöntem imzasına ref eklemek, dönüş değerinin referansla döndürüleceği anlamına gelir. Dönüş değeri, depolama konumuna başvurudur.
Bir değişkenin başka bir değişkene başvurmasını sağlamak için başvuru atamasını da kullanabilirsiniz. Tipik bir atama, sağ taraftaki değeri atamanın sol tarafındaki değişkene kopyalar.
Başvuru ataması, sağ taraftaki değişkenin bellek konumunu sol taraftaki değişkene kopyalar. şimdi ref özgün değişkenine başvuruyor:
int anInteger = 42; // assignment.
ref int location = ref anInteger; // ref assignment.
ref int sameLocation = ref location; // ref assignment
Console.WriteLine(location); // output: 42
sameLocation = 19; // assignment
Console.WriteLine(anInteger); // output: 19
Bir değişken atadığınızda değerini değiştirirsiniz. Bir değişkene başvuru atadığınızda, değişkenin referans ettiği şeyi değiştirirsiniz.
Değişkenleri kullanarak ref ile değerlerin depolama alanında doğrudan çalışabilir, referansla geçiş yapabilir ve referans ataması yapabilirsiniz. Derleyici tarafından zorunlu kılınan kapsam kuralları, doğrudan depolamayla çalışırken güvenliği sağlar.
ref readonly ve in değiştiricilerinin her ikisi de bağımsız değişkenin başvuru ile geçirilmesi gerektiğini ve yöntem içinde yeniden atanamayacağını belirtir. Fark, yöntemin ref readonly parametresini değişken olarak kullandığını gösterir. Yöntem, parametreyi yakalayabilir veya salt okunur başvuru ile döndürebilir. Böyle durumlarda değiştiriciyi ref readonly kullanmanız gerekir. Aksi takdirde değiştirici in daha fazla esneklik sunar. ref ya da in değiştiricisini bir ref readonly parametresi için bağımsız değişkene eklemezseniz, derleyici bir uyarı verir.
Başvuru güvenli bağlamı
C#, bir ref ifadesine başvurduğu depolama alanının artık geçerli olmadığında erişilememesini sağlamak için ref ifadelere yönelik kurallar içerir. Aşağıdaki örneği göz önünde bulundurun:
public ref int CantEscape()
{
int index = 42;
return ref index; // Error: index's ref safe context is the body of CantEscape
}
Derleyici, bir yöntemden yerel değişkene başvuru döndüremediğinizden bir hata bildirir. Çağıran, başvurulmakta olan depolama alanına erişemiyor.
Güvenli bağlam, bir ref ifadenin erişilmesinin veya değiştirilmesinin güvenli olduğu kapsamı tanımlar. Aşağıdaki tabloda değişken türleri için başvuru güvenli bağlamları listelenmiştir .
ref alanları bir class veya başvuru olmayan struct içinde bildirilemez, bu satırlar bu nedenle tabloda yer almıyor.
| Beyanname | referans güvenli bağlam |
|---|---|
| bağlantısız yerel | yerel değişkenin bildirildiği blok |
| ref olmayan parametre | geçerli yöntem |
ref, ref readonly, in parametresi |
çağırma yöntemi |
out parametresi |
geçerli yöntem |
class alan |
çağırma yöntemi |
referans olmayan struct alan |
geçerli yöntem |
ref alanı ref struct |
çağırma yöntemi |
Bir değişken, eğer ref çağıran yöntemse, döndürülebilir.
Başvuru güvenli bağlamı geçerli yöntem veya bir bloksa, ref dönüşe izin verilmez. Aşağıdaki kod parçacığında iki örnek gösterilmektedir. Bir üye alanı, çağıran yöntemin kapsamından erişilebilir, dolayısıyla sınıf veya yapı bir alanının başvuru güvenli bağlamı çağrılan yöntemdir.
veya ref değiştiricileri ile bir parametre için in yöntemin tamamıdır. Her ikisi de bir üye yönteminden döndürülebilir ref :
private int anIndex;
public ref int RetrieveIndexRef()
{
return ref anIndex;
}
public ref int RefMin(ref int left, ref int right)
{
if (left < right)
return ref left;
else
return ref right;
}
Uyarı
ref readonly veya in değiştiricisi bir parametreye uygulandığında, bu parametre ref readonly tarafından, ref tarafından değil, döndürülebilir.
Derleyici, bir başvurunun ref güvenli bağlamından kaçamamasını sağlar. Derleyici, depolama alanı geçerli olmadığında bir ifadeye erişilebilen kodu yanlışlıkla yazıp yazmadığınız algıladığından, parametreleri, refve ref return yerel değişkenleri güvenli bir ref şekilde kullanabilirsinizref.
Güvenli bağlam ve başvuru yapıları
ref struct türleri, güvenli bir şekilde kullanılabildiklerinden emin olmak için daha fazla kural gerektirir. Bir ref struct tür ref alanları içerebilir. Bunun için güvenli bir bağlamın tanıtılması gerekir. Çoğu tür için güvenli bağlam çağırma yöntemidir. Başka bir deyişle, ref struct olmayan bir değer her zaman bir yöntemden döndürülebilir.
Resmi olmayan şekilde, bir için ref struct, tüm ref alanlarına erişilebilen kapsamdır. Başka bir deyişle, tüm alanlarının ref kesişimidir. Aşağıdaki yöntem bir üye alanına bir ReadOnlySpan<char> döndürür, bu nedenle güvenli bağlamı yöntemidir:
private string longMessage = "This is a long message";
public ReadOnlySpan<char> Safe()
{
var span = longMessage.AsSpan();
return span;
}
Buna karşılık, aşağıdaki kod bir hata verir çünkü ref field 'nin Span<int> üyesi yığın üzerinde ayrılmış tamsayı dizisine başvurur. Yönteminden kaçamaz:
public Span<int> M()
{
int length = 3;
Span<int> numbers = stackalloc int[length];
for (var i = 0; i < length; i++)
{
numbers[i] = i;
}
return numbers; // Error! numbers can't escape this method.
}
Bellek türlerini birleştirme
Tanıtımı System.Span<T> ve System.Memory<T>, bellekle çalışmak için birleşik bir model sağlar.
System.ReadOnlySpan<T> ve System.ReadOnlyMemory<T> belleğe erişmek için salt okunur sürümler sağlayın. Tümü, benzer öğelerden oluşan bir diziyi depolayarak bir bellek bloğu üzerinde bir soyutlama sağlar. Fark, Span<T> ve ReadOnlySpan<T>'nin ref struct türleri olması, Memory<T> ve ReadOnlyMemory<T>'ün ise struct türleri olmasıdır. Yayılma alanları bir ref fieldiçerir. Bu nedenle, bir aralığın örnekleri güvenli bağlamını bırakamaz. 'nin güvenli bağlamıref struct, ref güvenli bağlamıdırref field.
Memory<T> ve ReadOnlyMemory<T> uygulaması bu kısıtlamayı ortadan kaldırır. Bellek arabelleklerine doğrudan erişmek için bu türleri kullanırsınız.
Ref güvenliği ile performansı geliştirin
Performansı geliştirmek için bu özelliklerin kullanılması şu görevleri içerir:
-
Ayırmalardan kaçının: Bir türü
class'denstruct'ye dönüştürdüğünüzde, depolanma biçimini değiştirirsiniz. Yerel değişkenler yığında depolanır. Kapsayıcı nesne tahsis edildiğinde üyeler satır içinde depolanır. Bu değişiklik, daha az ayırma anlamına gelir ve bu da çöp toplayıcının yaptığı işi azaltır. Ayrıca, atık toplayıcının daha az sıklıkta çalışması için bellek baskısını azaltabilir. -
Başvuru semantiğini koruma: Bir türü
class'denstruct'ye değiştirmek, bir değişkeni bir yönteme geçirme semantiğini değiştirir. Parametrelerinin durumunu değiştiren kodun değiştirilmesi gerekir. Parametresi artık birstructolduğuna göre, yöntemi özgün nesnenin bir kopyasını değiştiriyor. Bu parametreyi parametrerefolarak geçirerek özgün semantiği geri yükleyebilirsiniz. Bu değişiklik sonrasında yöntemi özgünstructdosyayı yeniden değiştirir. -
Veri kopyalamaktan kaçının: Daha büyük
structtürleri kopyalamak bazı kod yollarındaki performansı etkileyebilir. Daha büyük veri yapılarını değer yerine başvuru ile yöntemlere geçirmek içinrefdeğiştiricisini de ekleyebilirsiniz. -
Değişiklikleri kısıtla: Bir
structtür başvuruyla geçirildiğinde, çağrılan yöntem yapının durumunu değiştirebilir.refdeğiştiricisini, argümanın değiştirilemeyeceğini belirtmek içinref readonlyveyaindeğiştiricileriyle değiştirebilirsiniz. Yöntemin parametreyi yakalaması veya salt okunur referans ile döndürmesi durumlarındaref readonlytercih edin. Ayrıca, birreadonly struct'ün hangi üyelerinin değiştirilebileceği üzerinde daha fazla kontrol sağlamak içinstructüyelerine sahipreadonlyveyastructtürler oluşturabilirsiniz. -
Belleği doğrudan işleme: Bazı algoritmalar, veri yapılarını bir dizi öğe içeren bir bellek bloğu olarak ele alırken en verimli şekilde çalışır.
SpanveMemorytürleri, bellek bloklarına güvenli erişim sağlar.
Bu tekniklerin hiçbiri kod gerektirmez unsafe . Akıllıca kullanıldığında, daha önce yalnızca güvenli olmayan teknikler kullanarak mümkün olan güvenli koddan performans özelliklerini alabilirsiniz.
Bellek ayırmalarını azaltmaya yönelik öğretici derste teknikleri kendiniz deneyebilirsiniz.