Description
Overview
- Since jruby-openssl 0.9.8, Lookup.loadCertificateOrCRLFile calls Store.matchedObject, and it calls Certificate.matches method for each stored certificates.
- Certificate.matches method calls
x509.getSubjectX500Principal()
method. This method internally encodes aux certificate using Bouncy Castle's ASN1OutputStream. - This encoding procedure creates many objects.
- It impacts GC performance badly.
Background
We upgraded JRuby 9.0.0.0 to 9.0.5.0 and found that our application started consuming much more memory. This application uses httpclient.gem to fetch data from HTTPS server. Here is its code:
https://github.com/treasure-data/embulk-input-sfdc/blob/master/lib/embulk/input/sfdc_api/api.rb
Here is a screenshot of memory profiler:
This shows that 9.0.5.0 allocates objects more frequently and triggers GC frequently (2x - 3x more frequent).
Memory profiler shows that under Lookup.loadCertificateOrCRLFile
method, JRuby 9.0.0.0 doesn't allocate many objects but 9.0.5.0 allocates many objects at Store.addCertificate
in addition to regular allocation at PEMInputOutput.readPEM
:
Under Store.addCertificate
, following stack is allocating majority of objects:
- Store.matchedObject
- Certificate.matches
- X509AuxCertificate.getSubjectX500Principal
- ASN1OutputStream.writeObject
- DERSequence.encode
- ...
- DERSequence.encode
- ASN1OutputStream.writeObject
- X509AuxCertificate.getSubjectX500Principal
- Certificate.matches
I think that Store.matchedObject method is just a lookup method but X509AuxCertificate.getSubjectX500Principal is allocating many objects unexpectedly.
Expected behavior
I think that Store.matchedObject or Certificate.matches can cache the result of X509AuxCertificate.getSubjectX500Principal()
to reduce object allocation.
Workaround
Memory allocation becomes much less frequent if I add jruby.openssl.x509.lookup.cache=8
system property:
But this option is disabled by default now.