{"id":55,"date":"2024-02-26T15:54:00","date_gmt":"2024-02-26T15:54:00","guid":{"rendered":"https:\/\/rudnil.uber.space\/?p=55"},"modified":"2025-02-28T12:45:28","modified_gmt":"2025-02-28T12:45:28","slug":"memory-optimization-for-jaxb-parsing","status":"publish","type":"post","link":"https:\/\/blog.nilsrudolph.de\/?p=55","title":{"rendered":"Memory optimization for JAXB parsing"},"content":{"rendered":"\n<p>On some project we had a Java program that needed to parse a lot of small XML messages continuously that uses a lot of memory.<\/p>\n\n\n\n<p>After we made a heap dump and analyzed it we found the problem, a big chunk of the memory was used by Strings from the JAXB Objects. We had over 1000 times the string &#8220;de-de&#8221;.<\/p>\n\n\n\n<p>So we did a small optimization and reduced the memory usage by 30%.<\/p>\n\n\n\n<p>The solution was to register an <code>XMLAdapter<\/code> for <code>String<\/code> objects, that ensured that if a string occurs multiple times only on String instances is used and shared.<\/p>\n\n\n\n<p>Here is a (simplified) implementation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"java\" class=\"language-java\">package de.nilsrudolph.blog;\n\nimport jakarta.xml.bind.annotation.adapters.XmlAdapter;\n\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.function.Function;\n\npublic class CachingXmlAdapter extends XmlAdapter&lt;String, String&gt; {\n\n    private static final ConcurrentHashMap&lt;String, String&gt; STRING_CACHE = new ConcurrentHashMap&lt;&gt;();\n\n    @Override\n    public String unmarshal(String s) {\n        return STRING_CACHE.computeIfAbsent(s, Function.identity());\n    }\n\n    @Override\n    public String marshal(String s)  {\n        return s;\n    }\n}<\/code><\/pre>\n\n\n\n<p>For production use, the STRING_CACHE should probably be replaces by some other caching logic. A normal Map will never evict entries can become very big.<\/p>\n\n\n\n<p>Now you only need to register the <code>XMLAdapter<\/code>, for example by adding or editing the package-info.java file of the package containing the JAXB classes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"\">@XmlJavaTypeAdapters({\n        @XmlJavaTypeAdapter(value = CachingXmlAdapter.class, type = String.class)\n})\npackage de.nilsrudolph.blog;\n\nimport jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;\nimport jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapters;<\/code><\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>On some project we had a Java program that needed to parse a lot of small XML messages continuously that uses a lot of memory. After we made a heap dump and analyzed it we found the problem, a big chunk of the memory was used by Strings from the JAXB Objects. We had over [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-55","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/posts\/55","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=55"}],"version-history":[{"count":2,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/posts\/55\/revisions"}],"predecessor-version":[{"id":61,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=\/wp\/v2\/posts\/55\/revisions\/61"}],"wp:attachment":[{"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=55"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=55"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.nilsrudolph.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}