Problem/Motivation
I've recently encountered a place where the entity storage has been kept as property on the entity class. If the entity type doesn't support static cache then everything is fine, but if it doesn't then this might lead to a memory leak on each entity load, as then the the entity is written to the persistent cache and when a lot of entities are being loaded the serialized storage will get bigger and bigger and so each serialized entity.
Proposed resolution
We could prevent this automatically and there are the two options:
In EntityStorageBase::__sleep()
don't return the property for the static entity cache.
In DependencySerializationTrait::__sleep()
and ::__wakeup()
take care of entity storages kind of like taking care of service objects.
The first option feels like the more natural to do, as the static cache is part of the entity storage, but on the other side there is no point to serialize the storage object as this takes more memory and actually having different storage instances for the same entity type around might break things as well, therefore not serializing it should be the better option as this could prevent other bugs beside memory leaks.
Remaining tasks
User interface changes
API changes
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#9 | interdiff.txt | 1018 bytes | slasher13 |
#9 | 2939491-9.patch | 4.55 KB | slasher13 |
#4 | interdiff-2-4.txt | 1.35 KB | hchonov |
#4 | 2939491-4.patch | 4.55 KB | hchonov |
#2 | 2939491-2.patch | 3.2 KB | hchonov |
Comments
Comment #2
hchonovActually we could do the both options mentioned in the issue summary.
Comment #4
hchonovFixing the failing test for properly cloning content entities.
Comment #5
dawehnerDid you consider introducing an interface for classes to change the behaviour how they are serialized/unserialized when serializing/unserializing a different class?
This condition is weird:
A && !(B && !C)
, can't we simplify this toA && (!B || c)
. Not sure this is more readable to be honest.Comment #6
hchonovCould you please elaborate on this as I am not sure I fully understand what you mean?
I've just reused the expression from the existing code above and thought it would be better if it is the same at both places.
Comment #7
slasher13Had multiple "PHP Fatal error: Allowed memory size ..." issues. Didn't find the root cause, but applying this patch helps.
Comment #8
alexpottI agree with @dawehner that the if is really odd but double negatives are certainly confusing. I'd make this
if ($this->_entityStorages && (!$phpunit_bootstrap || $container->has('entity_type.manager'))) {
To avoid the double negative as it is simpler to reason about. I think the earlier use in the for loop is not the same expression because there is no double negative.
Comment #9
slasher13#8 done
Comment #10
BerdirAgreed, this is easier to read.
Comment #11
catchCommitted/pushed to 8.6.x and cherry-picked to 8.5.x. Thanks!