Skip to content
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

Optimize Jackson resource management in codecs #25910

Closed
robotmrv opened this issue Oct 13, 2020 · 1 comment
Closed

Optimize Jackson resource management in codecs #25910

robotmrv opened this issue Oct 13, 2020 · 1 comment
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@robotmrv
Copy link

robotmrv commented Oct 13, 2020

Affects: 5.2.9.RELEASE

Jackson2JsonEncoder does not release BufferRecycler resources (i.e. does not close JsonGenerator and does not release ByteArrayBuilder which use jackson BufferRecycler)
Benchmark https://github.com/robotmrv/jackson-encoder-jmh shows that resources release could improve performance especially for small Json objects (SMALL case execution time reduction: (7568-836)/7568*100% = 89% , and allocations reduction by (18912 - 904)/18912 * 100% = 95% ).

Benchmark                                                              (size)    Mode      Cnt         Score       Error   Units
EncoderBenchmark.standard                                               SMALL  sample  1242327      7568.757 ±   504.091   ns/op
EncoderBenchmark.standard:standard·p0.00                                SMALL  sample               1200.000               ns/op
EncoderBenchmark.standard:standard·p0.50                                SMALL  sample               4200.000               ns/op
EncoderBenchmark.standard:standard·p0.90                                SMALL  sample               5200.000               ns/op
EncoderBenchmark.standard:standard·p0.95                                SMALL  sample               5496.000               ns/op
EncoderBenchmark.standard:standard·p0.99                                SMALL  sample              17600.000               ns/op
EncoderBenchmark.standard:standard·p0.999                               SMALL  sample             656752.640               ns/op
EncoderBenchmark.standard:standard·p0.9999                              SMALL  sample            5092737.024               ns/op
EncoderBenchmark.standard:standard·p1.00                                SMALL  sample           63635456.000               ns/op
EncoderBenchmark.standard:·gc.alloc.rate                                SMALL  sample        3     16876.982 ± 15567.406  MB/sec
EncoderBenchmark.standard:·gc.alloc.rate.norm                           SMALL  sample        3     18912.820 ±     1.751    B/op
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space                       SMALL  sample        3     16984.177 ± 20148.650  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space.norm                  SMALL  sample        3     19025.003 ±  7094.976    B/op
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space                   SMALL  sample        3         0.276 ±     0.487  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space.norm              SMALL  sample        3         0.309 ±     0.257    B/op
EncoderBenchmark.standard:·gc.count                                     SMALL  sample        3       123.000              counts
EncoderBenchmark.standard:·gc.time                                      SMALL  sample        3        88.000                  ms
EncoderBenchmark.standard                                              MEDIUM  sample  1168448      6943.506 ±   221.997   ns/op
EncoderBenchmark.standard:standard·p0.00                               MEDIUM  sample               3000.000               ns/op
EncoderBenchmark.standard:standard·p0.50                               MEDIUM  sample               5096.000               ns/op
EncoderBenchmark.standard:standard·p0.90                               MEDIUM  sample               6096.000               ns/op
EncoderBenchmark.standard:standard·p0.95                               MEDIUM  sample               6496.000               ns/op
EncoderBenchmark.standard:standard·p0.99                               MEDIUM  sample              16096.000               ns/op
EncoderBenchmark.standard:standard·p0.999                              MEDIUM  sample             275968.000               ns/op
EncoderBenchmark.standard:standard·p0.9999                             MEDIUM  sample            2448839.475               ns/op
EncoderBenchmark.standard:standard·p1.00                               MEDIUM  sample           30343168.000               ns/op
EncoderBenchmark.standard:·gc.alloc.rate                               MEDIUM  sample        3     17321.737 ±  6117.869  MB/sec
EncoderBenchmark.standard:·gc.alloc.rate.norm                          MEDIUM  sample        3     20584.740 ±     0.986    B/op
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space                      MEDIUM  sample        3     17373.760 ±  8861.711  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space.norm                 MEDIUM  sample        3     20645.069 ±  5169.821    B/op
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space                  MEDIUM  sample        3         0.348 ±     1.126  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space.norm             MEDIUM  sample        3         0.414 ±     1.491    B/op
EncoderBenchmark.standard:·gc.count                                    MEDIUM  sample        3       156.000              counts
EncoderBenchmark.standard:·gc.time                                     MEDIUM  sample        3        89.000                  ms
EncoderBenchmark.standard                                                 BIG  sample  1108559     25400.314 ±   383.783   ns/op
EncoderBenchmark.standard:standard·p0.00                                  BIG  sample              21184.000               ns/op
EncoderBenchmark.standard:standard·p0.50                                  BIG  sample              22272.000               ns/op
EncoderBenchmark.standard:standard·p0.90                                  BIG  sample              23296.000               ns/op
EncoderBenchmark.standard:standard·p0.95                                  BIG  sample              24288.000               ns/op
EncoderBenchmark.standard:standard·p0.99                                  BIG  sample              58752.000               ns/op
EncoderBenchmark.standard:standard·p0.999                                 BIG  sample             515584.000               ns/op
EncoderBenchmark.standard:standard·p0.9999                                BIG  sample            3512631.296               ns/op
EncoderBenchmark.standard:standard·p1.00                                  BIG  sample           51118080.000               ns/op
EncoderBenchmark.standard:·gc.alloc.rate                                  BIG  sample        3      9092.443 ±  1508.929  MB/sec
EncoderBenchmark.standard:·gc.alloc.rate.norm                             BIG  sample        3     45650.467 ±     3.312    B/op
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space                         BIG  sample        3      9174.451 ±  3205.813  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Eden_Space.norm                    BIG  sample        3     46060.476 ± 11092.691    B/op
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space                     BIG  sample        3         0.323 ±     1.038  MB/sec
EncoderBenchmark.standard:·gc.churn.PS_Survivor_Space.norm                BIG  sample        3         1.620 ±     5.011    B/op
EncoderBenchmark.standard:·gc.count                                       BIG  sample        3       163.000              counts
EncoderBenchmark.standard:·gc.time                                        BIG  sample        3        90.000                  ms
EncoderBenchmark.withCloseAndRelease                                    SMALL  sample  1396264       836.310 ±   107.060   ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.00          SMALL  sample                500.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.50          SMALL  sample                600.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.90          SMALL  sample                600.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.95          SMALL  sample                700.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.99          SMALL  sample                700.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.999         SMALL  sample              19680.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.9999        SMALL  sample             442041.088               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p1.00          SMALL  sample           27131904.000               ns/op
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate                     SMALL  sample        3      7274.705 ±  5323.424  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate.norm                SMALL  sample        3       904.073 ±     0.186    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space            SMALL  sample        3      7329.033 ±  6542.575  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space.norm       SMALL  sample        3       910.611 ±   165.411    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space        SMALL  sample        3         0.291 ±     1.342  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space.norm   SMALL  sample        3         0.036 ±     0.171    B/op
EncoderBenchmark.withCloseAndRelease:·gc.count                          SMALL  sample        3       175.000              counts
EncoderBenchmark.withCloseAndRelease:·gc.time                           SMALL  sample        3        89.000                  ms
EncoderBenchmark.withCloseAndRelease                                   MEDIUM  sample  1343486      2877.905 ±   109.585   ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.00         MEDIUM  sample               2100.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.50         MEDIUM  sample               2400.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.90         MEDIUM  sample               2500.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.95         MEDIUM  sample               2600.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.99         MEDIUM  sample               3500.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.999        MEDIUM  sample              63520.832               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.9999       MEDIUM  sample             762522.931               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p1.00         MEDIUM  sample           14794752.000               ns/op
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate                    MEDIUM  sample        3      4904.697 ±   344.229  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate.norm               MEDIUM  sample        3      2536.282 ±     0.168    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space           MEDIUM  sample        3      4964.870 ±   516.275  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space.norm      MEDIUM  sample        3      2567.401 ±   213.382    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space       MEDIUM  sample        3         0.197 ±     1.073  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space.norm  MEDIUM  sample        3         0.102 ±     0.561    B/op
EncoderBenchmark.withCloseAndRelease:·gc.count                         MEDIUM  sample        3       127.000              counts
EncoderBenchmark.withCloseAndRelease:·gc.time                          MEDIUM  sample        3        77.000                  ms
EncoderBenchmark.withCloseAndRelease                                      BIG  sample  1172404     23765.922 ±   183.083   ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.00            BIG  sample              20672.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.50            BIG  sample              21600.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.90            BIG  sample              22496.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.95            BIG  sample              23072.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.99            BIG  sample              50944.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.999           BIG  sample             366592.000               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p0.9999          BIG  sample            1568845.824               ns/op
EncoderBenchmark.withCloseAndRelease:withCloseAndRelease·p1.00            BIG  sample           19070976.000               ns/op
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate                       BIG  sample        3      5693.537 ±   619.550  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.alloc.rate.norm                  BIG  sample        3     27100.606 ±     0.954    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space              BIG  sample        3      5857.821 ±  3192.046  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Eden_Space.norm         BIG  sample        3     27880.071 ± 12267.127    B/op
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space          BIG  sample        3         0.185 ±     0.779  MB/sec
EncoderBenchmark.withCloseAndRelease:·gc.churn.PS_Survivor_Space.norm     BIG  sample        3         0.879 ±     3.722    B/op
EncoderBenchmark.withCloseAndRelease:·gc.count                            BIG  sample        3       139.000              counts
EncoderBenchmark.withCloseAndRelease:·gc.time                             BIG  sample        3        77.000                  ms

Probably all places which use com.fasterxml.jackson.core.JsonFactory#_getBufferRecycler should be managed properly

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Oct 13, 2020
@bclozel bclozel self-assigned this Oct 14, 2020
@bclozel bclozel added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 20, 2020
@bclozel bclozel added this to the 5.2.10 milestone Oct 20, 2020
@bclozel bclozel changed the title Jackson2JsonEncoder does not release BufferRecycler resources Optimize Jackson resource management in codecs Oct 20, 2020
@bclozel
Copy link
Member

bclozel commented Oct 20, 2020

Thanks very much @robotmrv , this improvement will ship with 5.2.10 and the upcoming 5.3.0.

bclozel added a commit that referenced this issue Dec 8, 2020
Prior to this commit, a change introduced in gh-25910 would close the
`JsonGenerator` after it's been used for JSON serialization. This would
not only close it and recycle resources, but also flush the underlyning
buffer to the output.
In a case where the JSON serialization process would throw an exception,
the buffer would be still flushed to the response output. Before the
change introduced in gh-25910, the response body could be still empty at
that point and error handling could write an error body instead.

This commits only closes the `JsonGenerator` when serialization has been
successful.

Note that we're changing this in the spirit of backwards compatibility
in the 5.2.x line, but change this won't be merged forward on the 5.3.x
line, for several reasons:

* this behavior is not consistent. If the JSON output exceeds a
certain size, or if Jackson has been configured to flush after each
write, the response output might still contain an incomplete JSON
payload (just like before this change)

* this behavior is not consistent with the WebFlux and Messaging codecs,
which are flushing or closing the generator

* not closing the generator for error cases prevents resources from
being recycled as expected by Jackson

Fixes gh-26246
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants