JavaScript çöp toplama nedir?


Yanıtlar:


192

Eric Lippert bir süre önce bu konuyla ilgili ayrıntılı bir blog yazısı yazdı (ayrıca VBScript ile karşılaştırılıyor ). Daha doğrusu, JavaScript'e çok benzemesine rağmen Microsoft'un kendi ECMAScript uygulaması olan JScript hakkında yazdı . Davranışın büyük çoğunluğunun Internet Explorer'ın JavaScript motoru için aynı olacağını varsayabileceğinizi düşünürüm. Tabii ki, uygulama tarayıcıdan tarayıcıya değişecektir, ancak bazı ortak prensipleri alabileceğinizden ve bunları diğer tarayıcılara uygulayabileceğinizden şüpheleniyorum.

Şu sayfadan alıntı yapıldı:

JScript, istenmeyen bir markalama ve süpürme çöp toplayıcısı kullanır. Şöyle çalışır:

  • "Kapsamda" olan her değişkene "çöpçü" denir. Bir çöpçü, bir sayıya, bir nesneye, bir dizeye, her neyse başvurabilir. Çöpçülerin bir listesini tutarız - değişkenler kapsama girdiğinde çöpçü listesine, kapsam dışı olduklarında çöpçü listesinden çıkarılır.

  • Arada sırada çöp toplayıcı çalışıyor. İlk olarak her nesneye, değişkene, dizgiye vb. Bir "işareti" koyar - GC tarafından izlenen tüm bellek. (JScript, VARIANT veri yapısını dahili olarak kullanır ve bu yapıda çok fazla sayıda kullanılmayan bit vardır, bu yüzden bunlardan birini ayarladık.)

  • İkincisi, çöpçüler üzerindeki işareti ve çöpçü referanslarının geçişli kapanışını temizler. Eğer bir çöpçü nesnesi bir kazıcı-olmayan olmayan nesneye başvuruyorsa, o zaman kazıcı-olmayan ve atıfta bulunduğu her şeydeki bitleri temizleriz. (Önceki yazımdakinden farklı bir anlamda "kapanış" kelimesini kullanıyorum.)

  • Bu noktada, hala işaretlenen tüm belleğin, herhangi bir kapsam içi değişkenin herhangi bir yolundan erişilemeyen, ayrılmış bellek olduğunu biliyoruz. Tüm bu nesnelere, dairesel referansları yok eden kendilerini yıkmaları söylenir.

Çöp toplama temel amacı programcı izin vermektir değil o en azından nasıl çöp toplama işlerinin bir fikir olması her zaman faydalıdır - Elbette hayır bazen orada kaçıyor ait olsa, oluşturdukları nesnelerin ve kullanım bellek yönetimi hakkında endişe etmek .

Tarihsel not: cevabın daha önceki bir revizyonu deleteoperatöre yanlış referans verdi . JavaScript içinde operatör nesnenin özelliği kaldırır , ve tamamen farklı C / C ++ olarak.deletedelete


27
Apple kılavuzu kusurlu: autor deleteyanlış kullanıyor ; örneğin ilk örnekte, yerine delete fooolay dinleyicisini üzerinden kaldırmalı window.removeEventListener()ve daha sonra foo = nulldeğişkenin üzerine yazmak için kullanmalısınız ; IE'de delete window.foo(ama değil delete foo) fooküresel olsaydı da işe yarardı, ancak o zaman bile FF veya Opera'da olmazdı
Christoph

3
Eric'in makalesinin "yalnızca tarihi amaçlar için" düşünülmesi gerektiğini unutmayın. Ama yine de bilgilendirici.
Peter Ivan

2
Ayrıca not edin - IE 6 ve 7, istenmeyen bir markalama ve süpürme çöp toplayıcısını KULLANMAYIN. Çöp toplama ile ilgili dairesel referans sorunlarına karşı daha savunmasız olan basit bir referans sayma çöp toplayıcısı kullanırlar.
Doug

1
ECMAScript'ler deletebir ifade değil (yani:) tekli bir operatördür (bir ifade delete 0, delete 0, delete 3). Bir ifade ifadesi ile ifade edildiğinde ifade gibi görünür.
Hydroper

O zaman cevap şu anda modası geçmiş, 2012 itibariyle, modern tarayıcılar bir mark / sweep algorthm kullanıyor ... bu yüzden artık kapsama bağlı değil. Referanslama: developer.mozilla.org/en-US/docs/Web/JavaScript/…
sksallaj

52

DOM nesneleri söz konusu olduğunda dairesel referanslara dikkat edin:

JavaScript'te bellek sızıntı düzenleri

Belleğin yalnızca nesneye etkin bir başvuru olmadığında geri alınabileceğini unutmayın. Bazı JS motorları, iç işlevlerde gerçekte hangi değişkenlere başvurulduğunu kontrol etmeyecek ve yalnızca ek işlevlerin tüm yerel değişkenlerini koruyacağından, bu, kapanışları ve olay işleyicileriyle ortak bir tuzaktır.

İşte basit bir örnek:

function init() {
    var bigString = new Array(1000).join('xxx');
    var foo = document.getElementById('foo');
    foo.onclick = function() {
        // this might create a closure over `bigString`,
        // even if `bigString` isn't referenced anywhere!
    };
}

Etkin bir JS uygulaması bigString, olay işleyicisi etrafta olduğu sürece toplanamaz . Bu örneğin sorunu, ayarı çözmek için çeşitli yollar vardır bigString = nullsonunda init()( deleteirade yerel değişkenler ve fonksiyon argümanları için değil iş: deletenesnelerden kaldırır özellikleri ve değişken nesne erişilemez - Katı modda ES5 bile atacağım ReferenceErrorDenersen yerel bir değişkeni silmek için!).

Bellek tüketimini önemsiyorsanız, gereksiz kapanışlardan kaçınmanızı tavsiye ederim.


20
DOM dairesel referans hatası JScript'e özgüdür - IE'den başka tarayıcı yok. Aslında, ECMAScript spesifik olarak GC'nin bu döngülerle başa
çıkabilmesi

@olliej: ECMAScript spesifikasyonunda GC'den bahsetmiyorum .
Janus Troelsen


16

Bir blogdan alınan iyi teklif

DOM bileşeni, JScript bileşeni gibi "çöp toplanır" dır; bu, herhangi bir bileşenin içinde bir nesne oluşturup ardından bu nesnenin izini kaybederseniz, sonunda temizleneceğini gösterir.

Örneğin:

function makeABigObject() {
var bigArray = new Array(20000);
}

Bu işlevi çağırdığınızda, JScript bileşeni işlev içinde erişilebilen bir nesne (bigArray adlı) oluşturur. Ancak işlev geri döner dönmez, bigArray'ın “parçasını kaybedersiniz” çünkü artık ona başvurmanın bir yolu yoktur. JScript bileşeni, izini kaybettiğinizi fark eder ve böylece bigArray temizlenir - belleği geri kazanılır. Aynı şey DOM bileşeninde de çalışır. document.createElement('div')Veya benzer bir şey söylerseniz , DOM bileşeni sizin için bir nesne oluşturur. Bir şekilde nesnenin izini kaybettiğinizde, DOM bileşeni ilgili öğeyi temizler.


13

Bildiğim kadarıyla JavaScript'in nesneleri, nesneye hiç referans kalmadığında periyodik olarak toplanan çöplerdir. Otomatik olarak gerçekleşen bir şeydir, ancak nasıl çalıştığı hakkında daha fazla bilgi edinmek istiyorsanız, C ++ düzeyinde, WebKit'e veya V8 kaynak koduna

Tipik olarak bunu düşünmenize gerek yoktur, ancak IE 5.5 ve IE 6'nın eski sürümleri ve belki de mevcut sürümler gibi eski tarayıcılarda, kapaklar işaretlenmediğinde belleği tüketen dairesel referanslar oluşturacaktır. Kapatmalardan bahsettiğim özel durumda, dom nesnesine bir JavaScript başvurusu ve JavaScript nesnesine geri gönderilen bir DOM nesnesine bir nesne eklediğiniz zamandı. Temel olarak asla toplanamazdı ve sonunda işletim sisteminin kilitlenme oluşturmak için döngü yapan test uygulamalarında kararsız hale gelmesine neden olur. Pratikte bu sızıntılar genellikle küçüktür, ancak kodunuzu temiz tutmak için DOM nesnesine ilişkin JavaScript referansını silmeniz gerekir.

Genellikle, geri aldığınız JSON verileri gibi büyük nesnelere hemen başvurmak ve özellikle mobil web geliştirmede ne yapmanız gerekiyorsa onu yapmak için delete anahtar sözcüğünü kullanmak iyi bir fikirdir. Bu, GC'nin bir sonraki taramasının bu nesneyi kaldırmasına ve belleğini boşaltmasına neden olur.


Daha yeni IE sürümlerinde JavaScript -> DOM -> JavaScript döngüsel başvuru sorunu çözüldü mü? Eğer öyleyse, ne zamandan beri? Mimari açıdan çok derin ve sabitlenmenin pek mümkün olmadığını düşündüm. Kaynaklarınız var mı?
erikkallen

Sadece anekdot olarak. Standart modda çalışan IE 8'deki çılgın sızıntıları değil, kırık modda fark etmedim. Cevabımı ayarlayacağım.
Heat Miser

1
@erikkallen: Evet, GC hatası IE sürüm 8'de düzeltildi, çünkü eski olanlar çok naif bir çöp toplama algoritması kullanıyorlardı, bu da GC'yi birbirine yönlendiren bir çift nesneyi imkansız hale getirdi. Yeni mark-and-sweepstil algoritmaları bununla ilgilenir .
kumarharsh

6

çöp toplama (GC) artık gerekmeyen nesneleri kaldırarak otomatik bellek yönetimi biçimidir.

bellekle ilgili herhangi bir işlem şu adımları izleyin:

1 - ihtiyacınız olan bellek alanınızı ayırın

2 - biraz işlem yapın

3 - bu hafıza alanını boşaltın

artık hangi nesnelere gerek olmadığını tespit etmek için kullanılan iki ana algoritma vardır.

Referans sayma çöp toplama : Bu algoritma "artık bir nesneye ihtiyaç duyulmaz" tanımını "bir nesnenin kendisine referans veren başka bir nesnesi yok" olarak azaltır, referans noktası yoksa nesne kaldırılır

İşaretle ve süpür algoritması : her nesneyi kök kaynağa bağlayın. hiçbir nesne köke veya başka bir nesneye bağlanmaz. bu nesne kaldırılacak.

şu anda ikinci algoritmayı kullanan en modern tarayıcılar.


1
Ve bunun bir kaynağını eklemek için bkz. MDN: developer.mozilla.org/en-US/docs/Web/JavaScript/…
Xenos

4

"Bilgisayar biliminde, çöp toplama (GC) bir otomatik bellek yönetimi biçimidir. Çöp toplayıcı veya sadece toplayıcı, uygulama tarafından bir daha erişilemeyecek veya mutasyona uğramayacak nesneler tarafından kullanılan çöpü veya belleği geri almaya çalışır."

Tüm JavaScript motorlarının kendi çöp toplayıcıları vardır ve farklı olabilirler. Çoğu zaman onlarla uğraşmak zorunda değilsiniz çünkü sadece yapmaları gerekeni yaparlar.

Daha iyi kod yazmak çoğunlukla programlama ilkelerini, dili ve belirli uygulamaları ne kadar iyi bildiğinize bağlıdır.


1

JavaScript çöp toplama nedir?

bunu kontrol et

Bir web programcısının daha iyi kod yazmak için JavaScript çöp toplama işlemini anlaması ne önemlidir?

Javascript'te bellek ayırma ve ayırma umurumda değil. Bütün sorun Javascript yorumlayıcısına talep edilir. Javascript'te sızıntılar hala mümkündür, ancak bunlar yorumlayıcının hatalarıdır. Bu konuyla ilgileniyorsanız www.memorymanagement.org adresinden daha fazla bilgi edinebilirsiniz.


Bağladığınız makaledeki çeşitli bellek yönetim sistemlerinden hangisi JavaScript tarafından kullanılıyor? "Javascript'te sızıntılar hala mümkündür, ancak tercümanın hatalarıdır." - Bu, JS programcılarının tüm sorunu görmezden gelebileceği anlamına gelmez, örneğin IE kodunun eski sürümlerinde JS kodunuzda çalışabileceğiniz oldukça iyi bilinen bir JS <-> DOM dairesel referans sorunu vardır. Ayrıca, yolu JS kapanışları çalışma tasarım özelliği olmayan bir hata olduğunu, ancak "uygunsuz" kapanışları kullanırsanız (ben değilim istenenden daha belleğin büyük boyutta kravat olabilir değil 'em kullanmadığını söyleyerek).
nnnnnn

3
Bellek sızıntıları JavaScript'te bir canavardır. Basit bir "üniversite projesi" uygulaması yazıyorsanız, o zaman endişelenmeyin. Ancak, yüksek performanslı kurumsal düzeyde uygulamalar yazmaya başladığınızda, JavaScript'te bellek yönetimi bir zorunluluktur.
Doug

1

Windows'da Drip.exe'yi kullanarak bellek sızıntılarını bulabilir veya ücretsiz mem rutininizin çalışıp çalışmadığını kontrol edebilirsiniz.

Gerçekten basit, sadece bir web sitesi URL'si girin ve entegre IE oluşturucunun bellek tüketimini göreceksiniz. Ardından yenile düğmesine basın, bellek artarsa, web sayfasında bir yerde bir bellek sızıntısı buldunuz. Ancak bu, bellekte yer açmak için rutinlerin IE için çalışıp çalışmadığını görmek için de çok yararlıdır.


1

Referans türleri , nesneyi doğrudan atandığı değişkene depolamaz, bu nedenle bu örnekteki nesne değişkeni aslında nesne örneğini içermez. Bunun yerine, nesnenin var olduğu bellekteki konuma bir işaretçi (veya başvuru) tutar

var object = new Object();

bir değişkeni diğerine atarsanız, her değişken işaretçinin bir kopyasını alır ve her ikisi de hala aynı nesneyi bellekte kullanır.

var object1 = new Object();
var object2 = object1;

Bir nesneye işaret eden iki değişken

JavaScript çöp toplanmış bir dildir, bu nedenle referans türlerini kullandığınızda bellek ayırma konusunda endişelenmenize gerek yoktur. Ancak, çöp toplayıcının bu belleği boşaltabilmesi için artık ihtiyaç duymadığınız nesnelere başvurmamak en iyisidir . Bunu yapmanın en iyi yolu, nesne değişkenini null olarak ayarlamaktır.

var object1 = new Object();
// do something
object1 = null; // dereference

dereferencingNesnelerin , milyonlarca nesne kullanan çok büyük uygulamalarda özellikle önemlidir.

Odaklı JavaScript İlkelerinden Yardım - NICHOLAS C. ZAKAS

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.