-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid creating new PersistentList instance when adding empty collection #176
Conversation
val empty = emptyList<Int>() | ||
val emptyPersistent = empty.toPersistentList() | ||
|
||
assertTrue(emptyPersistent === empty.toPersistentList()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is assertSame
for this, which should give a slightly better error message should it ever fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, my preference is to use assertSame()
but I noticed that this particular file was using ===
instead of assertSame()
, and I try not to introduce new things for small changes like this. I'm happy to change it, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. It probably pre-dates instance equality being added to kotlin.test! No need to change, was just making sure it was known.
…f an empty collection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a maintainer, so best I can do is 👍
core/commonMain/src/implementations/immutableList/SmallPersistentVector.kt
Show resolved
Hide resolved
Thank you very much for the contribution! |
Problem
I encountered unexpected growth in memory usage while working on an library that uses
PersistentList
. I eventually realized that it is because I had many distinct instances of an emptyPersistentList
.I traced down the problem, starting with
toPersistentList()
, which I was using to convert all inputs before creating assembling it into my data model. ThetoPersistentList()
function takes the empty persistent list and adds all elements ofthis
to the empty list. When you add elements to aSmallPersistentVector
, it checks whether the combined size is less than or equal toMAX_BUFFER_SIZE
and if it is, it unconditionally creates a newSmallPersistentVector
instance.kotlinx.collections.immutable/core/commonMain/src/implementations/immutableList/SmallPersistentVector.kt
Lines 38 to 49 in 7fb0d74
This means that no-ops on small lists (such as adding two empty lists) always results in a new instance being created.
I verified that the problem only exists for
SmallPersistentVector
.PersistentVector
usesPersistentVectorBuilder
, which already has checks for adding an empty collection.What I am changing
I have added a check to
fun addAll(elements: Collection<E>): PersistentList<E>
andfun addAll(index: Int, c: Collection<E>): PersistentList<E>
to return early if the collection of elements to be added is empty.I have updated the tests to include missing no-op cases related to adding and removing empty collections in both
ImmutableListTest
andImmutableSetTest
, and I have added tests fortoPersistentMap()
,toPersistentSet()
, andtoPersistentList()
to ensure that when the receiver is an empty map/collection, they always return the same instance of persistent map/set/list.