Optimizasyon konularını ele aldığımız yazı serimizde bu yazının konusu “SSO (Short/Small String Optimization)”. Kulağa garip geliyor olabilir ancak SSO, C++ arkaplanda sizin yerinize yaptığı optimizasyonlardan bir tanesidir.

C++ Derleyicilerinde Optimizasyon Serisi:

Ne Anlama Gelmektedir?

Yazı dilinde bile kısa yazılar, uzun yazılara nazaran anlık olarak bile olsa daha akılda kalıcıdır. Bunun sebebi ise hatırlamak için çok fazla efor sarfetmemiz gerekmediğidir. Aynı olay yazılım tarafında da hafızadan yer kaplama olarak düşünebiliriz.

Küçük bir örnekle daha net bir şekilde anlatabileceğimi düşünüyorum. Bilgisayar hafızası için “Yazılım” ve “Ben bir yazılım mühendisiyim” aynı şeyi ifade etmiyor. Alt katmanlara inildiği zaman hafızadan ayrılan yer ve onlara erişim metodları değiştiği için yapılan geliştirmelerle bunlar üzerinde bir optimizasyon gerçekleştirilmiş.

stack ve heap kavramlarına aşina olduğunuzu düşünüyorum. İkisi de RAM’in mantıksal kavramlarıdır ancak aralarında bazı temel farklar vardır.

  • Stack’te otomatik değerler bulunur. Dinamik değerler genelde derleyiciler tarafından heap’te saklanır ama C++ standartları bunu zorunlu tutmaz.
  • Boyutsal olarak bakıldığında stack kendi içerisinde ayrılan kapasitenin aşılması durumunda derleyiciler bu durumu kontrol altında tutmaya çalışır ancak heap bunu sizin yapmanızı bekler.
  • Stack’e ulaşım stack_pointer kavramı sayesinde daha hızlı gerçekleşir. Heap bu konuda oldukça yavaş kalmaktadır.

Bunlardan neden bahsettiğime gelecek olursak, SSO sağlanması için kullanılan tanımlamalara göre küçük boyutlu string’ler ve daha büyük boyutlu veriler için birbirlerinden farklı alanlar ayrılır. Bu sayede “Yazılım” string’inin kayıt ve okuma işlemleri “Ben bir yazılım mühendisiyim” string’e göre çok daha hızlı işlem ve daha az hafıza ayırma ile yapılabilir.

İmplementasyon Detayları

C++ için birden farklı şekilde string tanımlama yöntemi kullanılabilir. Bu tanımlamalar bir tanesi

new char [size]

şeklinde yapılan sabit boyutlu tanımlamadır. Bu tanımlama ile sınırlı bir alan için bir yer ayrılır (allocation) ve onun üzerinden işlem yapılması sağlanır. Ancak bu bizim istediğimiz optimizasyon kriterlerinin tamamen dışındadır. Çünkü ilk olarak sabit boyutlu bir yer ayrılması yazılacak string için çok fazla olabilir ve bu da kaynak kullanımını kötü etkiler. Ayrıca yer ayrılan alan üzerinde kullanılabilecek maksimum alandan fazla bir veri yazılmak istenilebilir, bu yüzden veri kayıpları olabilir. Ayrıca C++’da dahili bir Garbage Collector metodu olmadığı için bu alanı kendimizin geri vermesi gerekecektir.

Bu veriyi dinamik bellekte tutmak istediğimizde ise veri kaybı olmadan tutabiliriz ancak okuma yazma işlemlerinde çok büyük vakit kayıplarına yol açabiliriz. Bunun yerine std::string implementasyonunu kullanabiliriz.

std::string ne sağlıyor?

std::string tanımlaması içerisinde boyut, kapasite ve verinin adresini tutmaktadır. Aslında bu veriler sayesinde arkaplanda sizin için verinin boyutuna göre hangi bellek alaninda tutulacağına karar verilmesini sağlar. Bu sayede veri erişimi ve kaynak kullanımı minimuma indirilmiş olur.

Bunu yaparken statik olarak belirlenmiş olan alanın aşılması durumunda otomatik olarak istenilen string’in boyutuna uygun bir alan ayrılır ve o alan üzerinden işlem yapılır. Kaynak ayırma işlemi birçok derleyici tarafından desteklenmektedir ve kendi aralarında farklılık göstermektedir. Araştırmalarında bulduğum ancak kendim test etmediğim bir görseli sizlerle paylaşıyorum.

Kısa string tanımlamaları compile-time’da yapıldığı için run-time’da karşılaşılacak problemlerin de önüne geçilmesini sağlar. Aşağıdaki kod bloğunu farklı işlemciler üzerinde çalıştırarak aradaki farkları kendiniz de görebilirsiniz.

#include <iostream>
#include <string>
 
using namespace std;
 
int main() {
    auto size = sizeof(string);
    auto capacity = string().capacity();
    auto small = string(capacity, '*');
    auto big = string(capacity + 1, '*');
 
    cout << "sizeof  : " << size << endl;
    cout << "Capacity: " << capacity << endl;
    cout << "Small   : " << small.capacity() << endl;
    cout << "Big     : " << big.capacity() << endl;
}


Optimizasyon konularını ele aldığım yazı serisinde bu yazımızda std::string kullanarak string’ler üzerinde nasıl optimizasyon gerçekleştirildiği konusundan bahsettim. Yanlış ve düzeltilmesi gereken bir nokta olduğunu düşünüyorsanız benimle iletişime geçebilirsiniz.

Bilgi hatalarının düzeltmesinden dolayı için Necati Ergin ve Doğa Oruç‘a teşekkür ederim.

Kaynaklar:

Author

Genel dünya problemleri ile çok ilgili olmasa da teknolojik gelişmeleri yakından takip eden, sistemleri geliştirmek için çalışmalar yapan, bolca kod yazmaya çalışan ve öğrendiklerini paylaşmaya çalışan birisi.

Write A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d blogcu bunu beğendi: