-
Notifications
You must be signed in to change notification settings - Fork 501
memory errors with Stackables objects and magic function __call() #389
Comments
well, i just saw a commit about magic methods.. and if I overwrite the setters explicity like this, things start working:
So the issue here is definitly the magic method __call .. any idea how I can still use this way of setting and getting member variables? Or should I just use "__set" and "__get" instead and wait for the next release? regards |
I will do some testing with __call, looks like a bug ... we utilize internal call handlers to implement protected and private method calls ... there might be a way to solve it. For the moment __get and __set should be fine if you are using code from master of github, the magic stuff is unreleased at the moment. Might be the weekend before I have a chance to look in detail, sorry about that ... |
thanks, no problem so far.. I implemented all the setters and getters for now. Even though the script runs till the end, it gets some memory errors while deconstructing objects if it runs a bit longer:
I played around a bit with my first test script to see if I can reconstruct it there too and even though the script is a bit longer now, I "proudly" present an example code that crashes (windows&linux again): <?php
class AbstractClass extends Stackable
{
public function compare($obj)
{
//return $this->compareByMemberAccess($obj);
return $this->compareByGetterAccess($obj); // no change :(, still crashes
}
public function compareByMemberAccess($obj) // compares member variables to each other (using direct member access)
{
if(get_class($obj) != get_class($this)) return false;
try
{
foreach(array_keys(get_object_vars($this)) as $elm)
{
if($this->$elm != null && $obj->$elm != null && $this->$elm instanceof AbstractClass)
{
if(!$this->$elm->compare($obj->$elm))
{
return false;
}
}
elseif($this->$elm != $obj->$elm)
{
return false;
}
}
return true;
}
catch(Exception $e)
{
return false;
}
}
public function compareByGetterAccess($obj) // compares member variables to each other (using getters)
{
if(get_class($obj) != get_class($this)) return false;
try
{
foreach(array_keys(get_object_vars($this)) as $elm)
{
$getter = "get".ucfirst($elm);
if($this->$getter() != null && $obj->$getter() != null && $this->$getter() instanceof AbstractClass)
{
if(!$this->$getter()->compare($obj->$getter()))
{
return false;
}
}
elseif($this->$getter() != $obj->$getter())
{
return false;
}
}
return true;
}
catch(Exception $e)
{
return false;
}
}
}
class A extends AbstractClass {
protected $numberX;
//somehow I only get a segfault if I add these member variables below - otherwise just memeory errors with invalid pointer, but no total crash (but maybe this was random)
protected $stringInstanceId;
protected $numberAuditTime;
protected $objectB;
protected $someValue1aaaabbbbbbbba;
protected $someValue2;
protected $someValue3;
protected $someValue4;
protected $someValue5;
protected $customId;
protected $asdfghjklasdfgasdfsdfdsf;
protected $aaaaaaaaaaaaaaaaaa;
public function getStringInstanceId()
{
return $this->stringInstanceId;
}
public function setNumberX($x) { $this->numberX = $x; }
public function getNumberX() { return $this->numberX; }
public function getNumberAuditTime() { return $this->numberAuditTime; }
public function getObjectB() { return $this->objectB; }
public function getSomeValue1aaaabbbbbbbba() { return $this->someValue1aaaabbbbbbbba; }
public function getSomeValue2() { return $this->someValue2; }
public function getSomeValue3() { return $this->someValue3; }
public function getSomeValue4() { return $this->someValue4; }
public function getSomeValue5() { return $this->someValue5; }
public function getCustomId() { return $this->customId; }
public function getAsdfghjklasdfgasdfsdfdsf() { return $this->asdfghjklasdfgasdfsdfdsf; }
public function getAaaaaaaaaaaaaaaaaa() { return $this->aaaaaaaaaaaaaaaaaa; }
}
class B extends AbstractClass {
protected $numberX;
protected $numberAuditTime;
protected $objectA;
public function setObjectA($a) { $this->objectA = $a; }
public function getObjectA() { return $this->objectA; }
public function setNumberX($x) { $this->numberX = $x; }
public function getNumberX() { return $this->numberX; }
public function getNumberAuditTime() { return $this->numberAuditTime; }
}
function dosomething()
{
static $allObjs=array();
$list = array();
for($i=0;$i<10;$i++)
{
$a = new A();
$a->setNumberX(rand(0,50));
$found=false;
foreach($allObjs as $o)
{
if($o->compare($a))
{
$a = $o;
$found = true;
//echo "using copy (a)\n";
break;
}
}
if(!$found) $allObjs[] = $a;
$list[] = $a;
$b = new B();
$b->setNumberX(rand(0,50));
$b->setObjectA($a);
$found=false;
foreach($allObjs as $o)
{
if($o->compare($b))
{
$b = $o;
$found = true;
//echo "using copy (b)\n";
break;
}
}
if(!$found) $allObjs[] = $b;
$list[] = $b;
}
return $list;
}
class TestThread extends Collectable
{
private $l;
public function __construct($list)
{
$this->l = $list;
}
public function run()
{
//usleep(rand(500,100000));
$l = $this->l;
foreach($l as $o)
{
echo get_class($o).";";
}
$this->setGarbage();
}
}
$pool = new Pool(10,'Worker'); // even more error messages, if pool size is equal to submitted amount of threads
//$pool = new Pool(4,'Worker');
for($i=0;$i<10;$i++)
{
$all[$i] = dosomething();
$pool->submit(new TestThread($all[$i]));
/** no change if using stackable instead of an array
* $data = new Stackable();
* foreach($all[$i] as $d)
* {
* $data[] = $d;
* }
* $pool->submit(new TestThread($data));*/
echo "good ".$i."\n";
}
$pool->shutdown();
die("done\n");
In Windows it's a zend_mm_heap corrupted error. Sometimes you have to execute the script a few times to get the error (based on rand - couldn't find time to narrow it down, the only thing I discovered so far is, that it's has nothing to do with the member variables like in the initial bug report) A big thanks for the extension, looking forward to see the last small memory issues fixed :) regards |
Execution without problem in 7:
Sorry it took so long, and sorry it's not the version you are probably using right now, but gotta look forward to 7 ;) |
I have a xml and construct a lot of classes out of it which have references to itself. The classes are just simple class objects with protected variables, using the magic php function I set and get variables from it.
e.g. class WmInstance extends AbstractClass
{
protected $wmInstance; // primary
protected $instanceId; // string
protected $auditTime; // string
}
the AbstractClass has the magic functions in it.
As soon as I extend the AbstractClass with "Stackable" (accesing the object in a non parallel way though - well it crashes also in a parallel way, but to keep things simple I tried to narrow it down), execution stack gets corrupted. It keeps crashing with erros like this one:
(tested on Windows and Linux, php 5.6.3, pthreads 2.0.10)
I think the issue lies somewhere in the attribute saving mechanism of threaded objects.. while narrowing down a testcase I found out it really depends on the object's attribute names (e.g. protected $a works, $protected $aaaaaa does not).
Here is an example code that crashes on windows&linux:
Try changing the protected member variable names and sometimes the crash disappears (it could be related to the length, but not sure..couldn't figure it out). Also it only happens on multiple calls of "dosomething()". First run seems always fine.
If you remove "extends Stackable" from AbstractClass, no php errors can be tracked either.
Let me know if I can provide something else to track this bug down.
Thanks
Simon
The text was updated successfully, but these errors were encountered: