为什么这个简单的php脚本会泄漏内存? [英] Why does this simple php script leak memory?

查看:77
本文介绍了为什么这个简单的php脚本会泄漏内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了希望避免将来php程序(双模块等)中的内存泄漏,我一直在研究一些简单的php脚本,它们会泄漏内存.

php专家能否帮助我找到有关此脚本的信息,从而导致内存使用率不断攀升?

尝试自己运行它,更改各种参数.结果很有趣.在这里:

<?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();

对我来说,输出是:

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

[已编辑,可取消设置更多对象成员的权限]

解决方案

不会释放变量使用的内存.当垃圾收集器"(因为PHP在版本5.3.0之前没有真正的垃圾收集器,只是一个主要在基元上工作的无内存例程)认为合适时,将释放内存.

而且,从技术上讲,您不需要调用 unset() ,因为$object变量仅限于您的函数范围.

这里是一个脚本来演示两者之间的区别.我修改了memstat()函数以显示自上次调用以来的内存差异.

<?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();
?>

如果您使用的是对象,请确保这些类实现 __unset() 以便允许 unset() 以正确清除资源.尽量避免使用诸如stdClass之类的可变结构类,或者为未位于类模板中的成员分配值,因为分配给它们的内存通常无法正确清除.

PHP 5.3.0及更高版本具有更好的垃圾收集器,但是默认情况下它是禁用的.要启用它,您必须调用 gc_enable() 一次. /p>

In hopes of trying to avoid future memory leaks in php programs (drupal modules, etc.) I've been messing around with simple php scripts that leak memory.

Could a php expert help me find what about this script causes the memory usage to continually climb?

Try running it yourself, changing various parameters. The results are interesting. Here it is:

<?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();

For me, the output is:

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

[edited to unset more object members]

解决方案

unset() doesn't free the memory used by a variable. The memory is freed when the "garbage collector" (in quotes since PHP didn't have a real garbage collector before version 5.3.0, just a memory free routine which worked mostly on primitives) sees fit.

Also, technically, you shouldn't need to call unset() since the $object variable is limited to the scope of your function.

Here is a script to demonstrate the difference. I modified your memstat() function to show the memory difference since the last call.

<?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();
?>

If you are using objects, make sure the classes implements __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 or assigning values to members which are not located in your class template as memory assigned to those are usually not cleared properly.

PHP 5.3.0 and up has a better garbage collector but it is disabled by default. To enable it, you must call gc_enable() once.

这篇关于为什么这个简单的php脚本会泄漏内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆