According to this question, the standard way to determine the memory size of an object in Java is by using java.lang.instrumentation. After to some research, it looks like there is no Scala specific way to achieve this, so the Java approach should also applies here.
Unfortunately, for a Scala programmer without Java background it is not fully straightforward to adapt this technique in Scala. My questions are:
Question 1
What exactly is happening here? I guess the reason why we have to put a class like ObjectSizeFetcher
in a separate JAR is to ensure that it is somehow loaded before the actual program where we want to use it. I assume it is not possible to use instrumentation without the Premain-Class
entry and the parameter -javaagent:TheJarContainingObjectFetcher.jar
?
Question 2
Is there a simple way to implement the complete work flow in SBT? Currently I only see a somewhat cumbersome solution: I first have to set up a secondary SBT project where I define ObjectSizeFetcher
and package it into a JAR. So far I did not figure out how to automatically add the Premain-Class
entry to the JAR during packaging, so I would have to solve that manually. Than I can add the resulting JAR to the local libraries of the project where I want to use getObjectSize
. For this project I now have to enable fork in run
and use javaOptions in run += "-javaagent:TheJarContainingObjectFetcher.jar"
. Is there a more simple (and less intrusive) work flow to quickly use instrumentation within an existing SBT project? Maybe I can tell SBT directly about a Premain-Class
to make this secondary JAR unnecessary?
Question 3
Would you recommend a completely different way to evaluate the memory usage of an object in Scala?
Answer 1: Yes, if you want iinstrumentation, you need to get an instance. You probably can't get it without Premain-Class and -javaagent.
Answer 2: You can (and may need to) use classloaders and create a very simple bootstrap project (in Java or in Scala with Proguard). There are two reasons:
The first reason: conveniency. You may use java.net.URLClassLoader to include standard Scala library and the classes directory of your project. You will not need to repackage it in JAR any more when testing.
The second reason: preventing JAR hell. You probably know that Scala is not binary compatible. You should also know that the Java agent is loaded with the application in the same classloader. If the classloader includes Scala library, application can't simply use another Scala version.
However, if the Java agent doesn't use directly Scala library (e.g. it is a bootstrap application and loads the real agent and its libraries in another classloader), the instrumented application is free to use any Scala library.
Answer 3: I would probably use instrumentation, too.
Answer 3: you can have a look to ktoso/sbt-jol
which displays the JOL (Java Object Layout), ie the analysis of object layout schemes in JVMs
// project/plugins.sbt
addSbtPlugin("pl.project13.sbt" % "sbt-jol" % pluginVersionHere)
It does include the size:
> jol:internals example.Entry
...
[info] example.Entry object internals:
[info] OFFSET SIZE TYPE DESCRIPTION VALUE
[info] 0 12 (object header) N/A
[info] 12 4 int Entry.value N/A
[info] 16 4 String Entry.key N/A
[info] 20 4 (loss due to the next object alignment)
[info] Instance size: 24 bytes
[info] Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With