Tutorials

Monitor memory consumption (Java Thread Dump)

Here we are, happily working on our project when, while trying to run the jstack command on a PID=1 process, we are confronted with the following error:   «Unable to get pid of LinuxThreads manager thread».

This happens because the process PID=1 is a reserved process of the operating system. So how can we fix it?

To execute the process, we are going to make a number of changes in the project to first start a «sh» process that later starts the Java process, leaving it all as follows:

Steps to take

1.- Create startJava.sh file

It must be at the same src height, Docker, JenkinsFile, with the Spring Boot boot line and profile:

java -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker,securityOff -jar /app.jar 

2.- Add the startJava.sh file to the container

We will do this after the packaging process (mvn).

We will edit the pom.xml file to add a plugin, in the build stage, that copies the .sh files to the target folder, so that this file can later be included in the Docker image, along with the .jar of the application.

<plugin> 
    <artifactId>maven-resources-plugin</artifactId> 
    <version>3.1.0</version> 
    <executions> 
        <execution> 
                    <id>copy-resource-one</id> 
                        <phase>package</phase> 
                      <goals> 
                        <goal>copy-resources</goal> 
                                </goals> 
                            <configuration> 
                                  <outputDirectory>target/</outputDirectory> 
                                  <resources> 
                                       <resource> 
                                                <directory>.</directory> 
                                                <includes> 
                                                    <include>*.sh</include> 
                                            </includes> 
                                    </resource> 
                            </resources> 
                    </configuration> 
            </execution> 
    </executions> 
</plugin> 

3.- Modify DockerFile file

We will add the following line after adding the Spring Boot application; that is to say: after this line, ADD *-exec.jar app.jar

ADD startJava.sh startJava.sh 

We will grant execution permissions and owner permissions to the created file:

RUN chown onesait:onesait startJava.sh && \
chmod +x startJava.sh

We will comment out the «ENTRYPOINT» line and add the following line:

CMD ["/bin/sh","-c", "/startJava.sh"] 

A complete DockerFile example would look like this:

ADD *-exec.jar app.jar
ADD startJava.sh startJava.sh

# logs folder
RUN mkdir -p /var/logs/smartindustry/scheduler/transport-etl && \
	mkdir ./target
	
# create onesait user/group
RUN addgroup -S onesait -g 433 && adduser -u 431 -S -g onesait -h /usr/local -s /sbin/nologin onesait 

RUN chown -R onesait:onesait /usr/local && \
    chown -R onesait:onesait /var/logs/smartindustry/scheduler/transport-etl && \
    chown -R onesait:onesait ./target && \
    chown onesait:onesait app.jar && \
    chmod -R 777 ./target && \
    chmod -R 777 /var/logs && \
    chmod -R 777 /usr/local && \
    chown onesait:onesait startJava.sh && \
    chmod +x startJava.sh

VOLUME ["/tmp", "/var/logs/smartindustry/scheduler/transport-etl"]
    
USER onesait
    
EXPOSE 8082

ENV JAVA_OPTS="$JAVA_OPTS -Xms512M -Xmx1G" \
    SERVER_NAME=localhost 

#ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dspring.profiles.active=docker,securityOff","-jar","/app.jar"]
#ENTRYPOINT ["/bin/sh", "-c", "set -e && java -Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=docker,securityOff -jar /app.jar"]
CMD ["/bin/sh","-c", "/startJava.sh"]
#CMD ["/startJava.sh"]

After performing these steps, the PID will be changed:

And that’s it. Now it’s possible to execute the command on the desired PID:

$ jstack -l 10
2020-06-28 12:36:56
Full thread dump OpenJDK 64-Bit Server VM (25.212-b04 mixed mode):
"Attach Listener" #40 daemon prio=9 os_prio=0 tid=0x00005576e5349000 nid=0x4c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   Locked ownable synchronizers:
        - None
"DestroyJavaVM" #39 prio=5 os_prio=0 tid=0x00005576e81ae000 nid=0xc waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   Locked ownable synchronizers:
        - None

Header image: Reka Illyes at Unsplash

✍🏻 Author(s)

Leave a Reply

Your email address will not be published. Required fields are marked *