Nesne havuzlarıyla statik bellek JavaScript'i

Colt McAnlis
Colt McAnlis

Giriş

Web oyununuzun / web uygulamanızın belirli bir süre sonra kötü performans gösterdiğine dair bir e-posta alırsınız. Kodunuzu incelersiniz, göze çarpan bir şey görmezsiniz. Sonra Chrome'un bellek performansı araçlarını açarsınız ve şunu görürsünüz:

Bellek zaman çizelgenizden bir anlık görüntü

İş arkadaşlarınızdan biri, hafızayla ilgili bir performans sorunu yaşadığınızı fark ettiği için kıkırdar.

Bellek grafiği görünümündeki bu testere dişi desen, kritik olabilecek bir performans sorunu hakkında çok bilgi vericidir. Bellek kullanımınız arttıkça zaman çizelgesi yakalamasında grafik alanının da büyüdüğünü görürsünüz. Grafikte ani bir düşüş olduğunda, Çöp Toplayıcı'nın çalıştığı ve referans verilen bellek nesnelerinizi temizlediği bir durum söz konusudur.

Testere dişi ne anlama gelir?

Bu tür bir grafikte, çok sayıda Çöp Toplama etkinliği gerçekleştiğini görebilirsiniz. Bu durum, web uygulamalarınızın performansına zarar verebilir. Bu makalede, performansınız üzerindeki etkiyi azaltmak için bellek kullanımınızı nasıl kontrol edeceğiniz açıklanmaktadır.

Çöp toplama ve performans maliyetleri

JavaScript'in bellek modeli, çöp toplayıcı olarak bilinen bir teknolojiye dayanır. Birçok dilde, programcı sistemin Hafıza Yığını'ndan hafıza ayırmaktan ve hafızayı boşaltmaktan doğrudan sorumludur. Ancak Çöp Toplayıcı sistemi bu görevi programcı adına yönetir. Yani programcı referansı kaldırdığında nesneler doğrudan bellekten serbest bırakılmaz. Bunun yerine, Çöp Toplayıcı'nın sezgisel kurallarının bunu yapmanın yararlı olduğuna karar verdiği daha sonraki bir zamanda serbest bırakılır. Bu karar süreci, Çöp Toplayıcı'nın etkin ve etkin olmayan nesneler üzerinde bazı istatistiksel analizler yapmasını gerektirir. Bu analizlerin yapılması zaman alır.

Çöp toplama, genellikle programcının hangi nesnelerin bellek ayırımını kaldıracağını ve bellek sistemine döndüreceğini belirtmesini gerektiren manuel bellek yönetiminin zıttı olarak gösterilir.

GC'nin belleği geri kazandığı işlem ücretsiz değildir. Genellikle işini yapmak için bir zaman aralığı alarak kullanılabilir performansınızı azaltır. Bununla birlikte, ne zaman çalışacağına karar veren sistemdir. Bu işlem üzerinde hiçbir kontrolünüz yoktur. Kod yürütülmesi sırasında herhangi bir zamanda GC darbesi gerçekleşebilir. Bu darbe, tamamlanana kadar kod yürütmeyi engeller. Bu darbenin süresi genellikle bilinmez. Programın belirli bir noktada belleği nasıl kullandığına bağlı olarak, çalıştırmanın biraz zaman alması normaldir.

Yüksek performanslı uygulamalar, kullanıcılara sorunsuz bir deneyim sunmak için tutarlı performans sınırlarına dayanır. Çöp toplayıcı sistemler, rastgele zamanlarda ve rastgele süreler boyunca çalışarak uygulamanın performans hedeflerini karşılaması için gereken kullanılabilir süreyi azalttığından bu hedefi kısa devre yaptırabilir.

Bellek değişimini azaltın, çöp toplama vergilerini azaltın

Belirtildiği gibi, bir dizi sezgisel kural, bir darbenin yararlı olacağı kadar sayıda etkin olmayan nesne olduğunu belirlediğinde bir GC darbesi gerçekleşir. Bu nedenle, Çöp Toplayıcı'nın uygulamanızdan aldığı süreyi azaltmanın anahtarı, mümkün olduğunca fazla aşırı nesne oluşturma ve bırakma durumunu ortadan kaldırmaktır. Sık sık nesne oluşturma/serbest bırakma işlemine "bellek değişimi" denir. Uygulamanızın ömrü boyunca bellek değişimini azaltabilirseniz GC'nin yürütmenizden aldığı süreyi de azaltmış olursunuz. Yani, oluşturulan ve yok edilen nesnelerin sayısını kaldırmanız / azaltmanız, yani bellek ayırmayı bırakmanız gerekir.

Bu işlem, anı grafiğinizi şuradan taşır :

Bellek zaman çizelgenizden bir anlık görüntü

şuna:

Statik Bellek JavaScript

Bu modelde, grafiğin artık testere dişi şeklinde bir modele sahip olmadığını, bunun yerine başlangıçta çok fazla büyüdüğünü ve zaman içinde yavaş yavaş arttığını görebilirsiniz. Bellek değişimi nedeniyle performans sorunları yaşıyorsanız bu tür bir grafik oluşturmanız gerekir.

Statik bellek JavaScript'e geçiş

Statik Bellek JavaScript, uygulamanızın başında, uygulamanın yaşam süresi boyunca ihtiyaç duyulacak tüm belleği önceden ayırmayı ve artık nesnelere ihtiyaç duyulmadığı için yürütme sırasında bu belleği yönetmeyi içeren bir tekniktir. Bu hedefe birkaç basit adımda yaklaşabiliriz:

  1. Çeşitli kullanım senaryoları için gerekli olan maksimum canlı bellek nesnesi sayısını (tür başına) belirlemek üzere uygulamanızı donatın
  2. Kodunuzu, bu maksimum tutarı önceden ayıracak şekilde yeniden uygulayın ve ardından ana belleğe gitmek yerine bunları manuel olarak alın/serbest bırakın.

Aslında 1. maddeyi gerçekleştirmek için 2. maddeyi biraz yapmamız gerekir. Bu nedenle, önce 2. maddeden başlayalım.

Nesne Havuzu

Basit bir ifadeyle, nesne birleştirme, aynı türü paylaşan kullanılmayan bir nesne grubunu tutma işlemidir. Kodunuz için yeni bir nesneye ihtiyaç duyduğunuzda sistem Hafıza Yığını'ndan yeni bir nesne ayırmak yerine havuzdaki kullanılmayan nesnelerden birini geri dönüştürürsünüz. Harici kod, nesneyle ilgili işlemlerini tamamladıktan sonra nesneyi ana belleğe bırakmak yerine havuza döndürür. Nesne koddan hiçbir zaman referansla ilişkisi kaldırılmadığı (yani silinmediği) için çöp toplanmayacaktır. Nesne havuzlarını kullanmak, belleğin kontrolünü programcıya geri verir ve çöp toplayıcının performans üzerindeki etkisini azaltır.

Bir uygulamanın yönettiği heterojen bir nesne türü grubu olduğundan, nesne havuzlarının düzgün bir şekilde kullanılması için uygulamanızın çalışma zamanında yüksek değişim yaşayan her tür için bir havuzunuz olması gerekir.

var newEntity = gEntityObjectPool.allocate();
newEntity.pos = {x: 215, y: 88};

//..... do some stuff with the object that we need to do

gEntityObjectPool.free(newEntity); //free the object when we're done
newEntity = null; //free this object reference

Uygulamaların büyük bir çoğunluğu için, yeni nesneler ayırma ihtiyacı açısından bir noktada sabit bir seviyeye ulaşırsınız. Uygulamanızı birden çok kez çalıştırarak bu üst sınırın ne olduğunu anlayabilir ve uygulamanızın başında bu sayıda nesneyi önceden ayırabilirsiniz.

Nesneleri önceden ayırma

Nesne havuzunu projenize uygulamak, uygulamanızın çalışma zamanında gerekli olan nesne sayısı için teorik bir maksimum değer sağlar. Sitenizi çeşitli test senaryolarında çalıştırdıktan sonra, ihtiyaç duyulacak bellek gereksinimleri türleri hakkında iyi bir fikir edinebilir, bu verileri bir yerde kataloglayabilir ve uygulamanız için bellek gereksinimlerinin üst sınırlarını anlamak üzere analiz edebilirsiniz.

Ardından, uygulamanızın gönderim sürümünde, tüm nesne havuzlarını belirli bir miktarda önceden dolduracak şekilde başlatma aşamasını ayarlayabilirsiniz. Bu işlem, tüm nesne başlatma işlemlerini uygulamanızın önüne getirir ve yürütülmesi sırasında dinamik olarak gerçekleşen tahsis miktarını azaltır.

function init() {
  //preallocate all our pools. 
  //Note that we keep each pool homogeneous wrt object types
  gEntityObjectPool.preAllocate(256);
  gDomObjectPool.preAllocate(888);
}

Seçtiğiniz miktar, uygulamanızın davranışıyla yakından ilgilidir. Bazen teorik maksimum değer en iyi seçenek olmayabilir. Örneğin, ortalama maksimum değeri seçmek, ileri düzey kullanıcı olmayanlar için daha küçük bir bellek kullanımı sağlayabilir.

Her sorunu çözen sihirli bir değnek değildir.

Statik bellek büyüme modellerinin avantajlı olabileceği bir uygulama sınıflandırması vardır. Ancak Chrome DevRel ekibinden Renato Mangini'nin de belirttiği gibi, bu yaklaşımın bazı dezavantajları vardır.

Sonuç

JavaScript'in web için ideal olmasının nedenlerinden biri, hızlı, eğlenceli ve kullanımı kolay bir dil olmasıdır. Bunun başlıca nedeni, söz dizimi kısıtlamalarına karşı düşük engel olması ve bellek sorunlarını sizin adınıza ele alması. Kod yazabilir ve yorucu işlerle ilgilenmesine izin verebilirsiniz. Ancak HTML5 oyunları gibi yüksek performanslı web uygulamaları için GC, genellikle kritik öneme sahip kare hızını azaltarak son kullanıcının deneyimini düşürebilir. Dikkatli bir şekilde ölçüm yaparak ve nesne havuzlarını kullanarak kare hızınız üzerindeki bu yükü azaltabilir ve bu zamanı daha da etkileyici şeyler için kullanabilirsiniz.

Kaynak Kod

Web'de nesne havuzlarının birçok uygulaması var. Bu nedenle, sizi bir başkasıyla daha sıkmayacağım. Bunun yerine, her birinin belirli uygulama ayrıntılarına sahip olduğu bu sayfalara yönlendireceğim. Her uygulama kullanımının belirli uygulama ihtiyaçları olabileceği göz önüne alındığında bu nokta önemlidir.

Referanslar