Neden bu basit php script bellek sızdırıyor nedir?

7 Cevap php

Ben bellek sızıntı basit php komut dosyaları ile karıştırmasını oldum php programlar (drupal modülleri, vb) gelecek bellek sızıntılarını önlemek için çalışıyor umuduyla.

Bir php uzmanı bana bu senaryo hakkında ne bellek kullanımı sürekli tırmanmaya neden bulmanıza yardımcı olabilir?

Çeşitli parametreleri değişiyor, bunu kendiniz çalıştırmayı deneyin. Sonuçlar ilginç. İşte:

<?php

function memstat() {
  print "current memory usage: ". memory_get_usage() . "\n";
}

function waste_lots_of_memory($iters) {
  $i = 0;
  $object = new StdClass;
  for (;$i < $iters; $i++) {
    $object->{"member_" . $i} = array("blah blah blha" => 12345);
    $object->{"membersonly_" . $i} = new StdClass;
    $object->{"onlymember"} = array("blah blah blha" => 12345);
  }
  unset($object);
}

function waste_a_little_less_memory($iters) {
  $i = 0;
  $object = new StdClass;
  for (;$i < $iters; $i++) {

    $object->{"member_" . $i} = array("blah blah blha" => 12345);
    $object->{"membersonly_" . $i} = new StdClass;
    $object->{"onlymember"} = array("blah blah blha" => 12345);

    unset($object->{"membersonly_". $i});
    unset($object->{"member_" . $i});
    unset($object->{"onlymember"});

  }
  unset($object);
}

memstat();

waste_a_little_less_memory(1000000);

memstat();

waste_lots_of_memory(10000);

memstat();

Benim için, çıktısı:

current memory usage: 73308
current memory usage: 74996
current memory usage: 506676

[Daha fazla nesne üyeleri unset düzenlenebilir]

7 Cevap

unset() değişkeni tarafından kullanılan belleği serbest değildir. "Çöp toplayıcı" zaman belleği serbest (PHP beri tırnak sürüm 5.3.0 önce gerçek bir çöp toplayıcı yoktu, çoğunlukla ilkel çalıştı sadece bir bellek ücretsiz rutin) uygun görür.

Ayrıca, teknik olarak, since the $object değişken, işlev kapsamı sınırlıdır unset() aramak gerekmez.

İşte farkı göstermek için bir betik. Ben son çağrı beri bellek farkı göstermek için memstat() işlevi değiştirilmiş.

<?php
function memdiff() {
    static $int = null;

    $current = memory_get_usage();

    if ($int === null) {
        $int = $current;
    } else {
        print ($current - $int) . "\n";
        $int = $current;
    }
}

function object_no_unset($iters) {
    $i = 0;
    $object = new StdClass;

    for (;$i < $iters; $i++) {
        $object->{"member_" . $i}= array("blah blah blha" => 12345);
        $object->{"membersonly_" . $i}= new StdClass;
        $object->{"onlymember"}= array("blah blah blha" => 12345);
    }
}

function object_parent_unset($iters) {
    $i = 0;
    $object = new StdClass;

    for (;$i < $iters; $i++) {
        $object->{"member_" . $i}= array("blah blah blha" => 12345);
        $object->{"membersonly_" . $i}= new StdClass;
        $object->{"onlymember"}= array("blah blah blha" => 12345);
    }

    unset ($object);
}

function object_item_unset($iters) {
    $i = 0;
    $object = new StdClass;

    for (;$i < $iters; $i++) {

        $object->{"member_" . $i}= array("blah blah blha" => 12345);
        $object->{"membersonly_" . $i}= new StdClass;
        $object->{"onlymember"}= array("blah blah blha" => 12345);

        unset ($object->{"membersonly_" . $i});
        unset ($object->{"member_" . $i});
        unset ($object->{"onlymember"});
    }
    unset ($object);
}

function array_no_unset($iters) {
    $i = 0;
    $object = array();

    for (;$i < $iters; $i++) {
        $object["member_" . $i] = array("blah blah blha" => 12345);
        $object["membersonly_" . $i] = new StdClass;
        $object["onlymember"] = array("blah blah blha" => 12345);
    }
}

function array_parent_unset($iters) {
    $i = 0;
    $object = array();

    for (;$i < $iters; $i++) {
        $object["member_" . $i] = array("blah blah blha" => 12345);
        $object["membersonly_" . $i] = new StdClass;
        $object["onlymember"] = array("blah blah blha" => 12345);
    }
    unset ($object);
}

function array_item_unset($iters) {
    $i = 0;
    $object = array();

    for (;$i < $iters; $i++) {
        $object["member_" . $i] = array("blah blah blha" => 12345);
        $object["membersonly_" . $i] = new StdClass;
        $object["onlymember"] = array("blah blah blha" => 12345);

        unset ($object["membersonly_" . $i]);
        unset ($object["member_" . $i]);
        unset ($object["onlymember"]);
    }
    unset ($object);
}

$iterations = 100000;

memdiff(); // Get initial memory usage

object_item_unset ($iterations);
memdiff();

object_parent_unset ($iterations);
memdiff();

object_no_unset ($iterations);
memdiff();

array_item_unset ($iterations);
memdiff();

array_parent_unset ($iterations);
memdiff();

array_no_unset ($iterations);
memdiff();
?>

Eğer nesneleri kullanıyorsanız, emin olun sınıflar uygular __unset() in order to allow unset() to properly clear resources. Try to avoid as much as possible the use of variable structure classes such as stdClass veya bu atanan bellek olarak sınıf şablonu bulunmayan üyelerine atama değerleri genellikle düzgün temizlenmez.

PHP 5.3.0 ve üstü daha iyi bir çöp toplayıcı vardır ancak varsayılan olarak devre dışıdır. Bunu etkinleştirmek için, bir kez gc_enable() çağırmanız gerekir.

memory_get_usage() "{[(1)"}]

Bu işletim sistemi tarafından işlem için ayrılan bellek miktarı var, not atanan değişkenler tarafından kullanılan bellek miktarı. PHP her zaman geri OS belleği serbest bırakmıyor - ancak yeni değişkenler tahsis edildiğinde bu bellek hala yeniden kullanılabilir.

Bu gösteren basit. Script için sonuna değiştirin:

memstat();
waste_lots_of_memory(10000);
memstat();
waste_lots_of_memory(10000);
memstat();

Doğru konum, ve PHP aslında bellek sızıntı Şimdi, eğer, bellek kullanım hızı iki kat büyümek görmelisiniz. Ancak, burada asıl sonuç:

current memory usage: 88272
current memory usage: 955792
current memory usage: 955808

Waste_lots_of_memory ilk çağırma sonra "serbest" bellek () ikinci çağırma tarafından yeniden kullanılır olmasıdır.

PHP ile benim 5 yıl içinde, ben saatlik bir süre içinde nesneler ve gigabayt veri milyonlarca işledik komut ve bir seferde aylarca çalıştırmak komut yazdım. PHP'nin bellek yönetimi büyük değil, ama olmak için dışarı yapıyoruz gibi neredeyse kadar kötü değil.

memory_get_usage os ayrılan ne kadar bellek php bildiriyor. Mutlaka kullanılan tüm değişkenlerin boyutuna uymamaktadır. Php bellek zirve kullanımı varsa, onu hemen bellek kullanılmayan miktarı dönmemeye karar verebilir. Sizin örnekte, fonksiyon waste_a_little_less_memory zamanla kullanılmayan değişkenleri kaldırılır. Bu nedenle en yüksek kullanım nispeten küçüktür. waste_lots_of_memory bunu ayırmayı önce değişkenlerin (kullanılan bellek = çok) bir sürü oluşturur. Yani yüksek kullanım çok daha büyüktür.

Memory_get_usage Benim anlayış () bu çıkışı geniş bir işletim sistemi yelpazesi ve sürüm faktörlere bağlı olabilir olmasıdır.

Daha da önemlisi, bir değişken unsetting anında, hafıza bulunuyor özgür sürecinde onu ayırması, ve işletim sistemi (bağımlı tekrar, bu operasyonun özellikleri faaliyet sistemi) geri vermez.

Kısacası, muhtemelen bellek sızıntıları bakmak için daha karmaşık bir kurulum gerekir.

Ben PHP bunun tam işleyişi hakkında emin değilim, ama null ayarlandığında diğer bazı dillerde diğer nesneleri içeren bir nesne, doğal null diğer nesneleri belirlemek değildir. Bu, bu nesnelere başvuru sonlandırır, ancak PHP Java anlamda "çöp toplama" yok gibi bireysel kaldırılana kadar, alt nesneler hafızada var.

Ben kullanıcı Katkıda Notes this comment inanmak unset () Eğer test kodu görüyorsanız hikaye anlatmak.

Ben bundan daha fazla yardımcı olabilir emin değilim.

memory_get_usage() does not returns the immediate memory usage, but stored memory to run the process. IN the case of a huge array unset($array_a) will not release memory but consume more according to the memory_get_usage() in my system...

$array_a="(SOME big array)";
$array_b="";
//copy array_a to array_b
for($line=0; $line<100;$line++){
$array_b[$line]=$array_a[$line];
}

unset($array_a); //having this shows actually a bigger consume
print_r($array_b);

echo memory_get_usage ();