{"id":3562,"date":"2017-08-31T14:47:29","date_gmt":"2017-08-31T13:47:29","guid":{"rendered":"https:\/\/www.gamlor.info\/wordpress\/?p=3562"},"modified":"2021-03-11T09:42:56","modified_gmt":"2021-03-11T08:42:56","slug":"javas-enum-values-hidden-allocations","status":"publish","type":"post","link":"https:\/\/www.gamlor.info\/wordpress\/2017\/08\/javas-enum-values-hidden-allocations\/","title":{"rendered":"Java&#8217;s Enum.values() Hidden Allocations"},"content":{"rendered":"<p>I recently profiled an app of mine. During profiling, I&#8217;ve noticed tons of array allocations. Something like:<\/p>\n<p><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness-1024x332.png\" alt=\"\" width=\"700\" height=\"227\" class=\"aligncenter size-large wp-image-3570\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness-1024x332.png 1024w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness-300x97.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness-768x249.png 768w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocation-madness.png 1311w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>Well easy, a quick grep for TypeInfo[] array. Nothing. Ah, quick grep for TypeInfo collections. Nothing! Huh? Where the hell do I allocate the array then?<br \/>\nOk, more profiling! So, I enabled flight recorder with &#8216;-XX:+UnlockCommercialFeatures -XX:+FlightRecorder&#8217;. Then did a recording with <a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javaseproducts\/mission-control\/index.html\">Java Mission Control<\/a>, capturing the allocation stack traces:<\/p>\n<p><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values-1024x507.png\" alt=\"\" width=\"700\" height=\"347\" class=\"aligncenter size-large wp-image-3572\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values-1024x507.png 1024w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values-300x149.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values-768x380.png 768w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/allocated-by-enum-values.png 1456w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>Ok, the TypeInfo.values() method allocates the memory. TypeInfo is a enum, and I&#8217;m using the built in values() method. The code looked something like this:<\/p>\n<script src=\"https:\/\/gist.github.com\/d3f5a7f143dbc894b4f43c4fcbaae79f.js?file=Enum-Allocation-Example.java\"><\/script><noscript><pre><code class=\"language-java java\">package info.gamlor.blog;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\nenum TypeInfo {\n    UNKNOWN(0),\n    INT(1),\n    STRING(2);\n\n    private final int id;\n\n    TypeInfo(int id) {\n        this.id = id;\n    }\n\n    public static TypeInfo findType(int type){\n        for (TypeInfo t : values()){\n            if(t.id == type){\n                return t;\n            }\n        }\n        return UNKNOWN;\n    }\n}\n\npublic class Main {\n    private static Random rnd = new Random();\n\n    public static void main(String[] args) throws Exception {\n        List&lt;TypeInfo&gt; parsedData = new ArrayList&lt;&gt;();\n        for (int i = 0; i &lt; 1000000000; i++) {\n            int idParsedFromWire = readTypeIdFromData(rnd);\n\n            TypeInfo type = TypeInfo.findType(idParsedFromWire);\n\n            \/\/ Pretend we use the type for the exampe\n            parsedData.add(type);\n            consumeData(parsedData);\n        }\n        System.out.println(parsedData.size());\n    }\n\n    private static void consumeData(List&lt;TypeInfo&gt; parsedData) {\n        \/\/ Parsed data is consumed\n        if(rnd.nextBoolean()){\n            parsedData.clear();\n        }\n    }\n\n    private static int readTypeIdFromData(Random rnd) throws InterruptedException {\n        \/\/ Data comes from the wire....let&#039;s run this example a bit slower\n        int idParsedFromWire = rnd.nextInt(16);\n        Thread.yield();\n        return idParsedFromWire;\n    }\n}\n<\/code><\/pre><\/noscript>\n<p>Do you see the allocation? Why should it allocate that many arrays? The Enum values are constant, so it should be able to initialize an array once?<br \/>\nOk, let&#8217;s take a closer look and decompile the class file:<\/p>\n<pre>\r\njavap -c TypeInfo.class | grep -A 10 values\r\n<\/pre>\n<p>And we get:<\/p>\n<pre>\r\n  public static info.gamlor.blog.TypeInfo[] values();\r\n    Code:\r\n       0: getstatic     #1                  \/\/ Field $VALUES:[Linfo\/gamlor\/blog\/TypeInfo;\r\n       3: invokevirtual #2                  \/\/ Method \"[Linfo\/gamlor\/blog\/TypeInfo;\".clone:()Ljava\/lang\/Object;\r\n       6: checkcast     #3                  \/\/ class \"[Linfo\/gamlor\/blog\/TypeInfo;\"\r\n       9: areturn\r\n<\/pre>\n<p>As we can see, it deferences a static array of the Enum values. Then it clones that array before returning it, causing an array allocation. Why does it do that? It is a defensive copy:<br \/>\nJava&#8217;s arrays are a mutable. If values() just returns the reference to the original array, then some code might change the array&#8217;s content. That creates havoc, since it would change what Enum.values() returns. Therefore, the defensive copy.<\/p>\n<div id=\"attachment_3573\" style=\"width: 958px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/enum-copies.jpg\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-3573\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/enum-copies.jpg\" alt=\"\" width=\"948\" height=\"500\" class=\"size-full wp-image-3573\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/enum-copies.jpg 948w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/enum-copies-300x158.jpg 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/enum-copies-768x405.jpg 768w\" sizes=\"(max-width: 948px) 100vw, 948px\" \/><\/a><p id=\"caption-attachment-3573\" class=\"wp-caption-text\">Safety First, Copy It<\/p><\/div>\n<p>So, after seeing this, it is easy to fix our code. We call Enum.values() once, cache the array and use it for the parsing:<\/p>\n<script src=\"https:\/\/gist.github.com\/d3f5a7f143dbc894b4f43c4fcbaae79f.js?file=Fix.java\"><\/script><noscript><pre><code class=\"language-java java\">\/\/ Enum.values() does a defensive copy and allocates an array on each call\n\/\/ To avoid that allocation, we call values() only once\nprivate static final TypeInfo[] ALL_VALUES = values();\n\npublic static TypeInfo findType(int type){\n    for (TypeInfo t : ALL_VALUES){\n        if(t.id == type){\n            return t;\n        }\n    }\n    return UNKNOWN;\n}<\/code><\/pre><\/noscript>\n<p>Et voila, the allocations are gone =)<\/p>\n<p><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed-1024x213.png\" alt=\"\" width=\"700\" height=\"146\" class=\"aligncenter size-large wp-image-3574\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed-1024x213.png 1024w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed-300x63.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed-768x160.png 768w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2017\/08\/fixed.png 1300w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I recently profiled an app of mine. During profiling, I&#8217;ve noticed tons of array allocations. Something like: Well easy, a quick grep for TypeInfo[] array. Nothing. Ah, quick grep for&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1,268,15,187],"tags":[311,295,293],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/3562"}],"collection":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/comments?post=3562"}],"version-history":[{"count":13,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/3562\/revisions"}],"predecessor-version":[{"id":3583,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/3562\/revisions\/3583"}],"wp:attachment":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/media?parent=3562"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/categories?post=3562"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/tags?post=3562"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}