8000 add singleton implementation of JsonObject to optimize memory usage by jnicoulaud-ledger · Pull Request #2353 · circe/circe · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

add singleton implementation of JsonObject to optimize memory usage #2353

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

Open
wants to merge 10 commits into
base: series/0.14.x
Choose a base branch
from

Conversation

jnicoulaud-ledger
Copy link
@jnicoulaud-ledger jnicoulaud-ledger commented Feb 27, 2025

This pull request optimizes memory usage in the edge case where there are many objects with only one field, default LinkedHashMap container has a lot of memory overhead in such cases.

Notes:

  • it looks like existing tests cover the new implementation correctly, let me know if more are needed
  • the benchmarks for folding/printing use a single field object, so this will make it biased. Not sure if I should add a more complex object / different benchmark ?

@jnicoulaud-ledger jnicoulaud-ledger marked this pull request as ready for review March 23, 2025 17:48
@plokhotnyuk
Copy link
Contributor
plokhotnyuk commented Mar 23, 2025

@jnicoulaud-ledger If you're looking to enhance the performance of parsing and serialization with circe AST even more, I'd like to introduce you to the jsoniter-scala-circe project. This library can significantly reduce latency and boost throughput, especially when using the jsoniter-core API for parsing and serialization from/to byte arrays or java.nio.ByteBuffers. Additionally, it offers improved safety, particularly when handling BigDecimal numbers, as discussed here.

Furthermore, the jsoniter-scala-benchmark module can be used to verify that there are no performance regressions in your pull requests. It includes real-world message samples from Google Maps, GitHub Actions, and Twitter APIs, ensuring that your changes maintain optimal performance.


fromLinkedHashMap(map)
val fieldsSeq = fields.iterator.toSeq
(fieldsSeq.size: @switch) match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should avoid converting the fields into a seq, just to use size, use sizeCompare or sizeIs on the Iterable and determine if its 0 or 1, or greater instead... this way you don't have to materialize the Seq, and sizeCompare is cheap in comparison.

fromLinkedHashMap(map)
val fieldsSeq = fields.iterator.toSeq
(fieldsSeq.size: @switch) match {
case 0 => empty
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty is actually sub-optimial as well, maybe we could create a dedicated empty type as well instead of it being final val empty: JsonObject = new MapAndVectorJsonObject(Map.empty, Vector.empty)


private[circe] final def fromMapAndVector(map: Map[String, Json], keys: Vector[String]): JsonObject =
new MapAndVectorJsonObject(map, keys)
(map.size: @switch) match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same critique on size above, use sizeCompare or sizeIs instead so a full traversal isn't used when it isn't needed.


private[circe] final def fromLinkedHashMap(map: LinkedHashMap[String, Json]): JsonObject =
new LinkedHashMapJsonObject(map)
(map.size: @switch) match {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0