> Theoretical it is thinkable we could either detect equal classes (but
> unlikely to happen ... if it's the same why do it in eval, zthus cost
> likely is higher than benefit in most cases?)

Thanks for your reply. I do it in eval() because schema.org has many types
(more than 600 at the moment), and each object ("Thing") can be an instance
of one or more of these types.
This creates an unmanageable number of possible combinations that I cannot
pre-compute, so I need to dynamically create a definition for an object
that implements an arbitrary number of interfaces.

> or unload the class once
> it's not needed anymore (which is hard to detect with reflection and
> other mechanisms which aren't bound to an instance's zval and also not
> cheap)

AFAIK, unloading a class is not possible from userland, I guess you're
talking about detecting this in PHP itself?

Anyway, that's an edge case, I found a workaround which is to keep a cache
of freshly created objects, indexed by interface name(s).
Anytime I request a combination of types that's already been handled in the
past, I return a clone of the cached object.

Even though the possible combinations of types are huge and impossible to
predict in advance, there are never more than a handful of such
combinations used in a single document, and I'd be surprised if there are
actually that many combinations actually used in the wild. So this should
hardly be a problem.

Thank you,
Ben


On Fri, 28 Jun 2019 at 17:59, Johannes Schlüter <johan...@schlueters.de>
wrote:

> On Fri, 2019-06-28 at 02:41 +0200, Benjamin Morel wrote:
> > Hi internals,
> >
> > I've tracked down a memory leak to an anonymous class created within
> > eval():
> >
> > ```
> > for ($i = 0; $i < 1000000; $i++) {
> >         $object = eval('return new class {};');
> >
> >         if ($i % 1000 == 0) {
> >                 echo memory_get_usage() . "\n";
> >         }
> > }
> >
> > ```
> >
> > The memory usage quickly ramps up and memory_limit is reached in
> > seconds.
> > Without eval(), the memory usage stays flat. I'm on 7.3.6.
> >
> > *Is this a bug?* Or is this some inherent limitation of eval() that
> > cannot
> > be fixed?
>
> I case this is non-trivial to fix. Each invocation recompile a new
> piece of code, which creates a new class.
>
> Similar to
>
>     for ($i = 0; $i < 1000000; $i++) {
>       eval("function f$i(){}");
>     }
>     f1();
>     f2();
>    ...
>
> or
>
>   for ($i = 0; $i < 1000000; $i++) {
>         file_put_contents("c$i.php", 'return new class {};');
>         $object = include "c$i.php";
>    }
>
> Theoretical it is thinkable we could either detect equal classes (but
> unlikely to happen ... if it's the same why do it in eval, zthus cost
> likely is higher than benefit in most cases?) or unload the class once
> it's not needed anymore (which is hard to detect with reflection and
> other mechanisms which aren't bound to an instance's zval and also not
> cheap)
>
> johannes
>
>

Reply via email to