What is the best way to gain insights in the memory footprint & usage of a native image that runs inside a dockercontainer?

5/27/2020

I have made a few services using Quarkus and want to explore some of the performance differences myself. Here I ran into the problem that the memory usage docker and kubernetes report on the container are way way lower than the memory usage reported by smallrye metrics or through a command like top from within the container. I now would like to gather more detailed information about the memory within the service to make an accurate as possible comparison, however I do not know how to get more detailed info.

GraalVM also offers tooling, like the visualVM, but it seems to only be able to work when the images are run natively (instead of in a docker container). The metrics from Smallrye don't offer the detail I'd like to see and things like NativeMemoryTracking aren't available (as far as I am aware).

Is there anything else I can explore or information I am missing?

-- MarissaB
docker
kubernetes
memory-footprint
performance
quarkus

1 Answer

5/27/2020

I use the following,

docker stats <containerId>

or

docker stats $(docker ps -q)

To see the memory usage of the whole container.

I use Metrics or:

ps -o "pid,rss,command" <pid> 

from the command line to see the memory usage.

Or just write your own Metric "Health check":

    @Liveness                                                                                                                                              
    @ApplicationScoped                                                                                                                                               
    public class InfoCheck implements HealthCheck {                                                                                             


    private final DecimalFormat nf = new DecimalFormat("###,### MB", new 
    DecimalFormatSymbols(new Locale("nl")));


    @ConfigProperty(name = "quarkus.application.name")                                                                                                                                                   
    String appName;


    @ConfigProperty(name = "app.version")                                                                                                                                                   
    String version;                                               


    @Override                                                                                                                                                                                               
    public HealthCheckResponse call() {                                                                                                            
        nf.setGroupingUsed(true);                                                                                                                                                               
        nf.setParseIntegerOnly(true);                                                                                                                                                                                                                   

        Runtime runtime = Runtime.getRuntime();                                
        long totalMemory = runtime.totalMemory();                                                                                                                                                       
        long freeMemory = runtime.freeMemory();                                                                                                                                                       
        long maxMemory = runtime.maxMemory();                                                                                                                                                                                                                                                                  

        return HealthCheckResponse.named(this.appName)                                                                                                                                                               
                .up()                                                                                                                                                               
                .withData("application.version", this.version)                                                                                                                                                            
                .withData("cpu.amount", runtime.availableProcessors())                                                                                                                                                              
                .withData("memory.free", nf.format(freeMemory / (1024 * 1024)))                                                                                                                                                               
                .withData("memory.allocated", nf.format(totalMemory / (1024 * 1024)))                                                                                                                                                              
                .withData("memory.total.free", nf.format((freeMemory + (maxMemory - totalMemory)) / (1024 * 1024)))

                .build();                                                       

        }                                                                                

    } 
-- Serkan
Source: StackOverflow