mtnr

A tech blog with fries on the side

Tag: java

  • Install Java on macOS Using SDKMAN!

    Update: I previously recommended using Homebrew and jEnv for managing Java installations, but I’ve since discovered SDKMAN! and find it to be a superior solution. It’s more streamlined, handles multiple SDKs beyond just Java, and doesn’t require Homebrew as a dependency.

    Managing multiple Java versions on macOS can be challenging, especially when different projects require different JDK versions. SDKMAN! (Software Development Kit Manager) offers an elegant solution that goes beyond just Java management.

    What is SDKMAN!?

    SDKMAN! is a tool for managing parallel versions of multiple Software Development Kits on Unix-based systems. Originally known as GVM (Groovy enVironment Manager), it provides a simple command-line interface for installing, switching, and managing various JVM-related tools. What makes SDKMAN! particularly attractive is that it works seamlessly on macOS, Linux, and Windows Subsystem for Linux (WSL).

    Installing SDKMAN!

    Installation is straightforward. Open your terminal and run:

    curl -s "https://get.sdkman.io" | bash

    After installation completes, either restart your terminal or run:

    source "$HOME/.sdkman/bin/sdkman-init.sh"

    Verify the installation by checking the version:

    sdk version

    Installing Java

    With SDKMAN! installed, you can now easily install Java. First, let’s see what versions are available:

    sdk list java

    This command displays all available Java distributions and versions. To install a specific version, use:

    sdk install java 17.0.13-tem

    You can install multiple versions and switch between them easily:

    sdk install java 21.0.5-tem
    sdk use java 21.0.5-tem

    To set a default Java version globally:

    sdk default java 17.0.13-tem

    Beyond Java: Other Development Tools

    One of SDKMAN!’s biggest advantages over jEnv is its ability to manage numerous other development tools. You can install build tools, frameworks, and other SDKs with the same simple commands:

    • Gradle: sdk install gradle
    • Maven: sdk install maven
    • Kotlin: sdk install kotlin
    • Scala: sdk install scala
    • Spring Boot CLI: sdk install springboot
    • Groovy: sdk install groovy

    To see all available SDKs:

    sdk list

    Useful Commands

    Here are some handy SDKMAN! commands to know:

    • sdk current – Show currently active SDK versions
    • sdk current java – Show currently active Java version
    • sdk upgrade – Upgrade all installed SDKs
    • sdk uninstall java 17.0.13-tem – Remove a specific version
    • sdk env – Switch to project-specific versions defined in .sdkmanrc

    Why SDKMAN! Over jEnv?

    While jEnv served me well, SDKMAN! offers several advantages:

    • No Homebrew dependency – SDKMAN! is self-contained
    • Manages more than just Java – one tool for your entire JVM ecosystem
    • Simpler installation and configuration
    • Active development and community support
    • Built-in update mechanism for both the tool and SDKs

    SDKMAN! has become my go-to tool for managing Java and related development tools on macOS. Its simplicity and comprehensive SDK support make it an excellent choice for Java developers working across multiple projects with varying requirements.

    Happy coding!

  • ๐Ÿ“Š Diagnosing Java Applications: Creating and Analyzing Thread & Heap Dumps

    When your Java application starts misbehaving – hanging, crashing, or consuming too much memory – thread and heap dumps are your go-to tools for root cause analysis. This post walks through how to create these dumps using the jstack, jmap, and jcmd tools, and suggests utilities for analyzing them effectively. Use jps to identify the process ID you’re interested in.


    ๐Ÿงต Thread Dumps: Capturing Thread States

    1. Using jstack

    jstack <PID> > threaddump.txt
    
    • Produces a snapshot of all thread states (blocked, runnable, waiting).
    • Great for diagnosing deadlocks, thread contention, and CPU spikes.

    2. Using jcmd

    jcmd <PID> Thread.print > threaddump.txt
    
    • More modern and flexible than jstack.
    • Lists thread locks and monitors.

    ๐Ÿง  Heap Dumps: Capturing Memory Snapshots

    1. Using jmap

    jmap -dump:live,format=b,file=heapdump.hprof <PID>
    
    • Dumps the live heap memory (excluding unreachable objects).
    • Useful for analyzing memory leaks and object retention.

    2. Using jcmd

    jcmd <PID> GC.heap_dump heapdump.hprof
    
    • Recommended over jmap for modern JVMs (especially with limited access).
    • Can work even when jmap fails due to permissions or restrictions.

    ๐Ÿงฐ Tools to Analyze Dumps

    ๐Ÿ” Thread Dump Analysis

    • jstack.review – Analyze java thread dumps from within the browser. No data will leave your computer when you click Analyze.
    • FastThread.io โ€“ Upload your dump and get a categorized summary.
    • TDA (Thread Dump Analyzer) โ€“ Desktop tool for visualizing thread interactions.

    ๐Ÿง  Heap Dump Analysis

    • Eclipse MAT (Memory Analyzer Tool) โ€“ Industry-standard tool for analyzing .hprof files.
    • VisualVM โ€“ Bundled with the JDK or available separately, it provides a GUI for live analysis and offline dump inspection.
    • YourKit โ€“ Commercial profiler with advanced heap analysis and leak detection.

    ๐Ÿ“ Final Thoughts

    Thread and heap dumps are crucial artifacts for JVM troubleshooting. While tools like jstack and jmap provide raw diagnostic data, leveraging jcmd offers greater flexibility and reliability on modern JVMs. Combined with powerful analysis tools, these techniques can help you uncover performance bottlenecks and memory issues before they escalate into outages.

    Happy debugging! ๐Ÿž

  • Install Java using Homebrew and jEnv on MacOS

    Sometimes it’s desirable to use different Java versions. Here’s one way how to do it on a Mac.

    Prerequisites

    If you haven’t already, install Homebrew as a first step.

    $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    Now, that Homebrew is installed, install jEnv, next. It’ll enable you to manage multiple Java installations and to switch easily amongst them.

    $ brew install jenv

    Follow the steps listed in the official jEnv documentation if you’re using a shell other than zsh to configure jEnv.

    You’ll find the steps necessary to configure zsh below.

    $ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
    $ echo 'eval "$(jenv init -)"' >> ~/.zshrc

    Install JDKs

    Now, that all pieces are in place, let’s install a JDK. You may chose whichever version you need. There is a list of available JDKs under https://formulae.brew.sh/formula/openjdk.

    $ brew install openjdk@17

    Manage JDKs

    In order to manage the newly installed JDK with jEnv, let’s make jEnv aware of it.

    $ jenv add /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home/

    You can chose to install additional JDKs now but we’ll check the available versions with jEnv, first.

    $ jenv versions
    * system (set by ~/.jenv/version)
      17
      17.0
      17.0.13
      openjdk64-17.0.13

    You can easily switch between versions using the following command.

    $ jenv global openjdk64-17.0.13

    This will enable the selected JDK on a global level. You may also chose to only enable it in a given directory by using the local instead of global command.

    You must restart you terminal for the changes to take effect.

    Happy coding!