C ++ Diline Özgü Endişeler
Her şeyden önce, C ++ tarafından zorunlu kılınan "yığın" veya "yığın" tahsisi yoktur . Blok kapsamlarındaki otomatik nesneler hakkında konuşuyorsanız, bunlar "ayrılmaz". Dinamik olarak tahsis edilmiş hafıza ile ilgili olduğu; (ikinci C "dinamik" ++ parlance olup. Btw, C otomatik depolama süresi kesinlikle "ayrılmış" aynı değildir) serbest deposu da, zorunlu olarak "yığın" ile, ikincisi genellikle (varsayılan) uygulamadır .
Soyut makine semantik kurallarına göre, otomatik nesneler hala belleği işgal etse de , uygun bir C ++ uygulamasının bunun önemli olmadığını kanıtlayabildiğinde (programın gözlemlenebilir davranışını değiştirmediğinde) bu gerçeği göz ardı etmesine izin verilir. Bu izin, nesnelerin belirli tasarımlarının atlanmasına izin vermek için as-if kuralı aynı zamanda olağan optimizasyonları mümkün kılan genel fıkra olan ISO C ++ 'daki (ve ISO C'de de hemen hemen aynı kural vardır). AS-if kuralının yanı sıra ISO C ++ 'ın da kopya seçim kuralları vardır tarafından verilir . Bu şekilde dahil olan yapıcı ve yıkıcı çağrıları atlanmıştır. Sonuç olarak, bu yapıcılarda ve yıkıcılarda bulunan otomatik nesneler (varsa), kaynak kodunun ima ettiği naif soyut semantiğe kıyasla ortadan kaldırılır.
Öte yandan, ücretsiz mağaza tahsisi kesinlikle tasarım gereği "tahsis" tir. ISO C ++ kuralları uyarınca böyle bir ayırma, bir ayırma işlevinin çağrılmasıyla gerçekleştirilebilir . Ancak, ISO C ++ 14 olduğundan, belirli durumlarda genel ayırma işlevi (yani ) çağrılarının birleştirilmesine izin veren yeni (if-as) olmayan bir kural vardır::operator new
. Dolayısıyla, dinamik ayırma işlemlerinin parçaları da otomatik nesneler gibi işlem yapmayabilir.
Tahsis fonksiyonları bellek kaynaklarını tahsis eder. Nesneler, ayırıcılar kullanılarak tahsisat bazında ayrıca tahsis edilebilir. Otomatik nesneler için doğrudan sunulur - temel belleğe erişilebilir ve diğer nesnelere (yerleştirme yoluyla new
) bellek sağlamak için kullanılabilir , ancak bu serbest mağaza olarak çok mantıklı değildir, çünkü kaynakları başka bir yerde.
Diğer tüm endişeler C ++ kapsamı dışındadır. Bununla birlikte, yine de önemli olabilirler.
C ++ Uygulamaları Hakkında
C ++, birleştirilmiş etkinleştirme kayıtlarını veya bazı birinci sınıf süreklilikleri (örneğin ünlüler tarafından call/cc
) ortaya çıkarmaz , etkinleştirme kayıt çerçevelerini doğrudan değiştirmenin bir yolu yoktur - uygulamanın otomatik nesneleri yerleştirmesi gerekir. Temel uygulama ile (taşınabilir olmayan) birlikte çalışma (satır içi montaj kodu gibi "yerel" taşınabilir olmayan kod) olduğunda, çerçevelerin temel tahsisinin ihmal edilmesi oldukça önemsiz olabilir. Örneğin, çağrılan işlev satır içine alındığında, çerçeveler başkalarıyla etkin bir şekilde birleştirilebilir, bu nedenle "ayırma" nın ne olduğunu göstermenin bir yolu yoktur.
Bununla birlikte, birlikte işlerliklere saygı duyulduktan sonra, işler karmaşıklaşmaktadır. Tipik bir C ++ uygulaması , yerel (ISA düzeyi makine) koduyla paylaşılan ikili sınır olarak bazı çağrı kurallarıyla birlikte ISA (yönerge kümesi mimarisi) üzerinde birlikte çalışabilme yeteneğini ortaya koyacaktır . Bu , genellikle doğrudan ISA düzeyinde bir kayıt tarafından tutulan (muhtemelen erişmek için belirli makine talimatları ile) yığın işaretçisini korurken, açıkça maliyetlidir . Yığın işaretçisi (şu anda etkin) işlev çağrısının üst çerçevesinin sınırını gösterir. Bir işlev çağrısı girildiğinde, yeni bir çerçeve gerekir ve yığın işaretçisi gerekli çerçeve boyutundan daha küçük olmayan bir değerle eklenir veya çıkarılır (ISA kuralına bağlı olarak). Sonra çerçeve söylenir tahsis edilirNe zaman işlemlerden sonra yığın işaretçi. İşlev parametreleri, çağrı için kullanılan çağrı kuralına bağlı olarak yığın çerçevesine de geçirilebilir. Çerçeve, C ++ kaynak kodu tarafından belirtilen otomatik nesnelerin (muhtemelen parametreler dahil) belleğini tutabilir. Bu tür uygulamalar anlamında, bu nesneler "tahsis edilir". Kontrol işlev çağrısından çıktığında, çerçeve artık gerekli değildir, genellikle yığın işaretçisini çağrıdan önceki duruma geri getirerek serbest bırakılır (daha önce çağrı kuralına göre kaydedilir). Bu "anlaşma" olarak görülebilir. Bu işlemler etkinleştirme kaydını etkili bir şekilde bir LIFO veri yapısı haline getirir, bu nedenle buna genellikle " (çağrı) yığını " denir .
Çoğu C ++ uygulaması (özellikle ISA düzeyindeki yerel kodu hedefleyen ve derleme dilini hemen çıktı olarak kullanan) bu tür benzer stratejiler kullandığından, bu tür kafa karıştırıcı bir "ayırma" düzeni popülerdir. Bu tür tahsisler (anlaşmaların yanı sıra) makine döngüleri harcar ve modern CPU mikro mimarileri, ortak kod deseni için donanım tarafından uygulanan karmaşık optimizasyonlara sahip olsa bile (optimize edilmemiş) çağrılar sık olduğunda pahalı olabilir. Yığın motoru uygulama PUSH
/ POP
talimatlar).
Ancak yine de, genel olarak, yığın çerçeve tahsisinin maliyetinin, yüzlerce (milyonlarca değilse ) serbest mağazayı çalıştıran (tamamen optimize edilmedikçe) bir tahsis fonksiyonuna yapılan çağrıdan önemli ölçüde daha düşük olduğu doğrudur . :-) yığın işaretçisini ve diğer durumları korumak için işlemler. Ayırma işlevleri genellikle barındırılan ortam tarafından sağlanan API'yi temel alır (örn. İşletim sistemi tarafından sağlanan çalışma zamanı). İşlev çağrıları için otomatik nesneleri tutma amacından farklı olarak, bu tür ayırmalar genel amaçlıdır, bu nedenle yığın gibi çerçeve yapısına sahip olmazlar. Geleneksel olarak, havuz depolama alanından yığın (veya birkaç yığın) adı verilen alan ayırırlar. "Yığın" konseptinden farklı olarak, burada "yığın" kavramı kullanılan veri yapısını göstermez;onlarca yıl önceki erken dil uygulamalarından türemiştir. (BTW, çağrı yığını genellikle program veya iş parçacığı başlangıcında yığın tarafından ortamdan sabit veya kullanıcı tarafından belirtilen boyutta ayrılır.) Kullanım durumlarının doğası, bir yığından ayırma ve ayırma işlemlerini (push veya pop'dan çok daha karmaşık hale getirir) yığın çerçeveleri) ve donanım tarafından doğrudan optimize edilmesi pek mümkün değildir.
Bellek Erişimi Üzerindeki Etkileri
Her zamanki yığın tahsisi her zaman yeni çerçeveyi en üste koyar, bu yüzden oldukça iyi bir konuma sahiptir. Bu önbellek dostudur. OTOH, serbest depoda rastgele tahsis edilen belleğin böyle bir özelliği yoktur. ISO C ++ 17'den beri, tarafından sağlanan havuz kaynağı şablonları vardır <memory>
. Böyle bir arayüzün doğrudan amacı, ardışık tahsislerin sonuçlarının bellekte birbirine yakın olmasına izin vermektir. Bu, bu stratejinin genellikle modern uygulamalardaki performans için iyi olduğunu, örneğin modern mimarilerde önbellek dostu olduğunu kabul eder. Bu, tahsis yerine erişim performansı ile ilgilidir .
eşzamanlılık
Belleğe eşzamanlı erişim beklentisi yığın ve yığınlar arasında farklı etkilere neden olabilir. Bir çağrı yığını genellikle yalnızca bir C ++ uygulamasında bir yürütme iş parçacığına aittir. OTOH, yığınlar genellikle bir işlemde dişler arasında paylaşılır . Bu yığınlar için, tahsis ve yeniden konumlandırma işlevleri paylaşılan iç idari veri yapısını veri yarışından korumak zorundadır. Sonuç olarak, yığın ayırma ve ayırma işlemleri, iç eşitleme işlemleri nedeniyle ek yüke sahip olabilir.
Alan Verimliliği
Kullanım durumlarının ve dahili veri yapılarının doğası gereği yığınlar, dahili bellek parçalanmasından muzdarip olabilir , ancak yığınlar bunu yapmaz. Bunun bellek ayırma performansı üzerinde doğrudan etkisi yoktur, ancak sanal belleğe sahip bir sistemde , düşük alan verimliliği bellek erişiminin genel performansını bozabilir. Bu, HDD fiziksel bellek değişimi olarak kullanıldığında özellikle korkunçtur. Oldukça uzun bir gecikmeye neden olabilir - bazen milyarlarca döngü.
Yığın Tahsislerinin Sınırlamaları
Her ne kadar yığın tahsisleri performansta gerçekte yığın tahsislerinden daha üstün olsa da, kesinlikle yığın tahsislerinin her zaman yığın tahsislerinin yerini alabileceği anlamına gelmez.
İlk olarak, ISO C ++ ile taşınabilir bir şekilde çalışma zamanında belirtilen boyutta yığın üzerinde alan ayırmanın bir yolu yoktur. alloca
G ++ 'ın VLA (değişken uzunluk dizisi) gibi uygulamalar tarafından sağlanan uzantılar vardır , ancak bunlardan kaçınmak için nedenler vardır. (IIRC, Linux kaynağı son zamanlarda VLA kullanımını kaldırmaktadır.) (Ayrıca ISO C99'un VLA'yı zorunlu kıldığını, ancak ISO C11'in desteği isteğe bağlı hale getirdiğini unutmayın.)
İkincisi, yığın boşluğu yorgunluğunu tespit etmek için güvenilir ve taşınabilir bir yol yoktur. Buna genellikle yığın taşması (hmm, bu sitenin etimolojisi) denir , ancak muhtemelen daha doğrusu yığın taşması olarak adlandırılır . Gerçekte, bu genellikle geçersiz bellek erişimine neden olur ve programın durumu daha sonra bozulur (... veya daha da kötüsü, bir güvenlik deliği). Aslında, ISO C ++ 'da "yığın" kavramı yoktur ve kaynak tükendiğinde tanımsız davranış haline getirir . Otomatik nesneler için ne kadar alan kalması gerektiğine dikkat edin.
Yığın alanı tükenirse, çok fazla etkin işlev çağrısından veya otomatik nesnelerin yanlış kullanılmasından kaynaklanabilecek yığınta çok fazla nesne tahsis edilir. Bu gibi durumlar, hataların varlığını önerebilir, örn. Doğru çıkış koşulları olmadan özyinelemeli bir işlev çağrısı.
Bununla birlikte, bazen derin yinelemeli çağrılar istenir. Sınırsız aktif çağrıların desteklenmesi gereken dillerin uygulamalarında (çağrı derinliğinin sadece toplam hafıza ile sınırlı olduğu yerlerde), (çağdaş) yerel çağrı yığınını doğrudan tipik C ++ uygulamaları gibi hedef dil aktivasyon kaydı olarak kullanmak imkansızdır . Bu soruna geçici bir çözüm bulmak için, etkinleştirme kayıtlarının oluşturulmasının alternatif yollarına ihtiyaç vardır. Örneğin, SML / NJ açıkça yığın üzerinde kareler ayırır ve kaktüs yığınları kullanır . Bu tür aktivasyon kayıt çerçevelerinin karmaşık tahsisi genellikle çağrı yığını çerçeveleri kadar hızlı değildir. Bununla birlikte, bu tür diller, uygun kuyruk özyineleme, nesne dilinde doğrudan yığın tahsisi (yani, dilde "nesne" referans olarak saklanmaz, ancak paylaşılmayan C ++ nesnelerine bire bir eşleştirilebilen yerel ilkel değerler) daha da karmaşıktır genel olarak performans cezası. Bu dilleri uygulamak için C ++ kullanırken, performans etkilerini tahmin etmek zordur.