How do I produce a heap dump with only a JRE? - java

We have a JRE installed on our production environment, but not a JDK. The versions of the JRE and OS are below.
[me#mymachine ~]$ java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
[me#mymachine ~]$ uname -a
Linux mymachine.mydomain.com 3.10.35-43.137.amzn1.x86_64 #1 SMP Wed Apr 2 09:36:59 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
It doesn’t appear as if the jmap tool is present anywhere on the system, and without root access, I’m not in a position to install it in any system location. What can I do to get a heap dump (i.e. produce a .hprof file)?
Also, we're using JBoss 7.1.3.AS if that matters.

Use jattach, a tool created by JVM hacker Andrei Pangin. It's tiny (24KB), works with just JRE and supports Linux containers.
jattach PID-OF-JAVA dumpheap <path to heap dump file>

Built-in tools like jmap, jconsole, and jvisualvm are only available in a JDK. Another option is to add the VM argument -XX:+HeapDumpOnOutOfMemoryError which tells the JVM to automatically generate a heap dump when an OutOfMemoryError occurs, and the argument -XX:HeapDumpPath to specify the path for the heap dump.
If you cannot upgrade your JRE to use tools like the ones in the server JRE 7 (http://www.oracle.com/technetwork/java/javase/downloads/server-jre7-downloads-1931105.html), you may have to consider third-party profiling tools like JProfiler or ones list here.

The only way seems to be to zip your local SDK6 and put it somewhere on the server. Then open a remote console and from within the bin directory of that SDK dump the JRE.
If your client forbids uploading executable files, you are out of luck of course.

kill -3 <pid>
thread dump will be sent in to <TOMCAT_HOME>/logs/catalina.out file
OR use combination below :
-XX:+UnlockDiagnosticVMOptions -XX:+LogVMOutput -XX:LogFile=~/jvm.log
if you want to redirect., but for that you have to run your process through command line.

Related

How to examine a jar file when the JDK is not installed

I have a docker container which runs a jar file. Normally, it needs the JRE but not the JDK, so the JDK is not installed in the container.
During development, I sometimes want to examine the jar file that is inside the container, usually to do something like
jar tf Some.jar | grep SomeClassThatShouldBeThere
or possibly run java to see the method signatures on a class.
Is there a simpler way to do this than installing the JDK in the container or copying the files out of the container? I am hoping for an answer like
java oracle.java.internal.Jar <args>
possibly with a class path element.
Since this is for one-off debugging, I do not mind accessing a private API that might change in the next release.
My JRE version is
# java -version
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-1)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-1, mixed mode)
The OS is
# uname -a
Linux c5891bfce794 4.9.93-linuxkit-aufs #1 SMP Wed Jun 6 16:55:56 UTC 2018 x86_64 GNU/Linux

Tomcat 7 + JNI: UnsatisfiedLinkError: cannot open shared object file: No such file or directory

Here's my problem: I have a WAR file which contains my webapp, and a .jar in its WEB-INF/lib which depends on .so files to be present on the host where Tomcat is running. When I deploy my WAR file through the app manager, I get an UnsatisfiedLinkError: file not found in the startup logs when the JNI wrapper class is loaded from the .jar. When I look in the directory where the linked libraries are, they are clearly present, and have world read and execute permissions, and I've even changed the owner to be the same run-as user executing tomcat. I am fairly certain this is a permissions problem, because I can execute the WAR file on the command line, and I do not get the error. I'm hoping that someone can spot something I have missed, or direct me to some Tomcat documentation I've misread.
Here's the full text of the error when deployed via Tomcat manager:
07 Apr 2017 10:45:53,140 [ERROR] [... omitted irrelevant log output ...] java.lang.UnsatisfiedLinkError: /opt/omitted-sdk-name/linux_x86_64/bin/libjni_emdq.so: libemdq.so: cannot open shared object file: No such file or directory
If I shut down tomcat via systemctl stop tomcat and execute my war file like this (as root), I do not get the UnsatisfiedLinkError:
java -Djava.library.path=/opt/omitted-sdk-name/linux_x86_64/bin -jar /path/to/my/app##0.1.war
Some other useful info:
CentOS 7
Fresh, vanilla install via yum (no deviations from default config, except to enable the admin user on the manager and switch the default jvm).
/usr/sbin/tomcat version shows:
Server version: Apache Tomcat/7.0.69
Server built: Nov 6 2016 01:55:51 UTC
Server number: 7.0.69.0
OS Name: Linux
OS Version: 3.10.0-514.10.2.el7.x86_64
Architecture: amd64
JVM Version: 1.8.0_121-b13
JVM Vendor: Oracle Corporation
Tomcat is running as user tomcat
I've tried changing ownership from root to tomcat of all the .so files in this sdk. Changing owners did not change the actual behavior. For example, this owner/mode yields the problem - same owner as the tomcat run-as user, and full read+executable permission, which I expected would have fixed things:
[root#omitted-host bin]# ls -la | grep emdq
-rwxr-xr-x 1 tomcat tomcat 403153 Nov 10 03:10 libemdq.so
-rwxr-xr-x 1 tomcat tomcat 76850 Nov 10 03:11 libjni_emdq.so
EDIT: There seems to be two versions of Java on this machine. The one in root's path is 1.8.0_77 and the one configured for tomcat is 1.8.0_121:
[root#omitted-host tomcat]# java -version
java version "1.8.0_77"
Java(TM) SE Runtime Environment (build 1.8.0_77-b03)
Java HotSpot(TM) 64-Bit Server VM (build 25.77-b03, mixed mode)
[root#omitted-host tomcat]# /etc/alternatives/jre_1.8.0_openjdk/bin/java -version
openjdk version "1.8.0_121"
OpenJDK Runtime Environment (build 1.8.0_121-b13)
OpenJDK 64-Bit Server VM (build 25.121-b13, mixed mode)
output of file on the two .so in question shows they are 64-bit libs, so I don't think there's a problem with running in a 64-bit JVM:
[root#omitted-host bin]# file libjni_emdq.so
libjni_emdq.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
[root#omitted-host bin]# file libemdq.so
libemdq.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped
I have these lines in a file in $CATALINA_HOME/conf/conf.d/omittedname.conf. At some point in the past, I had them in tomcat.conf but either location seems to yield the same results.
MY_BIN="/opt/omitted-sdk-name/linux_x86_64/bin"
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$MY_BIN"
JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$MY_BIN -Djava.security.egd=file:/dev/./urandom -Djava.awt.headless=true -XX:+UseConcMarkSweepGC"
# needed to run the application
JAVA_OPTS="$JAVA_OPTS -Dprofile=test"
EDIT: after posting this, I noticed that root has a different jvm in its path. Java version above was edited too.
[root#omitted-host tomcat]# echo $PATH
/java/jdk1.8.0_77/bin:/opt/omitted-sdk-name/linux_x86_64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
Is there anything else I can try looking at? Do I possibly need to add a java.io.FilePermissions permission?
Also, just a humble statement that I am aware of the implications of running/owning things as root. My goal is just to get back to a working tomcat manager configuration to un-break this development server.
This answer is less than satisfying, but it was the key to solving my problem. I had to move the statement LD_LIBRARY_PATH=/opt/omitted-sdk-name/linux_x86_64/bin from $CATALINA_HOME/conf/conf.d/myapp.conf to $CATALINA_HOME/conf/tomcat.conf. After I did this, the UnsatisfiedLinkError disappeared.

Webstorm on centos 6.5

I've downloaded and extracted the tar file, but when I try to run the webstorm.sh file, I get the error:
"No JDK found. Please validate either WEBIDE_JDK, JDK_HOME or JAVA_HOME environment variable points to valid JDK installation.
I have Java installed:
[root#local.host]# java -version
java version "1.7.0_51"
OpenJDK Runtime Environment (rhel-2.4.4.1.el6_5-x86_64 u51-b02)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)
[root#local.host]# ls -lah /etc/alternative/java
lrwxrwxrwx. 1 root root 46 Jan 27 23:06 /etc/alternatives/java -> /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
I've also set the environment path, although I'm not 100% certain of it's correctness. Contents of .bash_profile:
PATH=$PATH:$HOME/bin
export PATH
export JDK_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin
export JAVA_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin
export PATH=$PATH:/usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin
What am I missing/doing wrong?
If you check the System Requirements and Installation page of WebStorm's website, you will see the following requirements for Linux...
System Requirements
Intel Pentium III/800 MHz or higher (or compatible)
512 MB RAM minimum, 1 GB RAM recommended
1024x768 minimum screen resolution
Oracle (Sun) JDK 1.6 or higher. Open JDK is not supported.
GNOME or KDE desktop.
And as confirmed by your system...
OpenJDK Runtime Environment (rhel-2.4.4.1.el6_5-x86_64 u51-b02)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)
This is why your WebStorm is complaining about a valid JDK installation.
As cited in WebStorm's website, the article Swapping OpenJDK for Sun JDK on Ubuntu can be useful to you.
The Sun JDK and OpenJDK are contained within the same installer. OpenJDK is used by default. After downloading and installing the JDK from the Oracle site, to specifically use Sun JDK, the following command must be run:
[root#local.host]# alternatives --install /usr/bin/java java /usr/java/latest/jre/bin/java 200000

Change Default Java VM to Client

I installed Oracle's Java on Fedora 17, and I noticed that when using the command java -version it returns this
java version "1.7.0_05"
Java(TM) SE Runtime Environment (build 1.7.0_05-b05)
Java HotSpot(TM) 64-Bit Server VM (build 23.1-b03, mixed mode)
Java seems to run the -server option by default. The help text came up as
-server to select the "server" VM
The default VM is server,
because you are running on a server-class machine.
Is there any way to change the default to client?
The default setting is defined in the file jvm.cfg. A content like
-client KNOWN
-server KNOWN
defines the client as the default.
-server KNOWN
-client KNOWN
sets the server as the default.
Source: www.rgagnon.com/javadetails/java-0566.html
jvm.cfg location
Unknown Mac OS X version:
/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/jre/lib/jvm.cfg
Mac OS X version 10.9 without installing JDK:
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/jvm.cfg
Mac OS X version 10.9 with installed JDK version 1.8.0_u92:
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jvm.cfg
You can find your jvm.cfg from the command line (Terminal.app) using the command $ locate /jvm.cfg. You might need to update your locate database first, using the command: $ sudo /usr/libexec/locate.updatedb
From the docs:
Note: For J2SE 5.0, the definition of a server-class machine is one
with at least 2 CPUs and at least 2GB of physical memory.
So there doesn't seem any way to alter the server-class machine detection technique, I'm guessing you will have to stick to passing the -client VM argument if you need it on your machine.
Also worth noting is that this page is for Java 5, so things might be different with Java 6 and higher.
Starting with Java 5, you can specify this as an option to the JVM:
the -client option will make the VM start in client mode. In this mode, the start-up will be much faster.
the -server option will make the VM start in server mode. The start-up will be slower, but in the long run, it will execute faster.
See this question for more details about the differences about the 2 modes.
If you do not specify these options, the VM will check to see if you have at least 2 CPUs and at least 2 GB RAM. If you do, then it will start in server mode.
You can see the tables about how these decisions are made:
here for Java 5
here for Java 6 and
here for Java 7
FYI: they are all the same.

How to make sure I'm using the "server" JVM?

Sun's JVM comes in two flavors: -client and -server, where the Server VM is supposed to be optimized for long running processes, and is recommended for server applications.
When I run java with no parameters, it displays the usage options, which includes the following text:
The default VM is server,
because you are running on a server-class machine.
Having seen this, I didn't bother to add the -server to the process startup command.
However, on a recent JVM crash log, I noticed the following line near the end of the file:
vm_info: Java HotSpot(TM) Client VM (14.0-b16) for linux-x86 JRE (1.6.0_14-b08), built on May 21 2009 02:01:47 by "java_re" with gcc 3.2.1-7a (J2SE release)
It seems to me that Java is using the Client VM, despite what it says in the help message. I'm going to add the -server option to my startup command, but now I'm suspicious. So my question is: is there a way to make sure that the VM I'm running in is really the Server VM, without resorting to forcing a JVM crash?
The OS is ubuntu 8.04, but I'm using JDK 1.6.0_14 which I downloaded from Sun's website.
You can do
System.out.println(System.getProperty("java.vm.name"));
Which on my machine returns either:
Java HotSpot(TM) Client VM
or
Java HotSpot(TM) 64-Bit Server VM
Of course you shouldn't do anything critical based on this value, as it will probably change in the future, and will be completely different on another JVM.
I had a very similar question which I asked on ServerFault. I would say, if you care which version is run, always use -client or -server.
Well, if you explicitly start with the -server command line prompt, you are running in server mode. You can check that with this:
ManagementFactory.getRuntimeMXBean().getInputArguments();
You can look at RuntimeMXBean which may open up more information, but that would have to be tested on the specific JVM you are running.
Without writing any single line of code, if you use JConsole to connect to your JVM, under 'VM Summary' tab, it should say exactly which (server or client) Virtual Machine is being monitored.
For example,
Virtual Machine: OpenJDK Server VM version 1.6.0-b09
To remotely monitor your JVM using JConsole, simply enable the JMX (Java Management Extensions) agent by starting JVM with the following System Properties
> java.rmi.server.hostname=[your server IP/Name] // without this, on linux, jconsole will fail to connect to the remote server where JVM is running
> com.sun.management.jmxremote.authenticate=false
> com.sun.management.jmxremote.ssl=false
> com.sun.management.jmxremote.port=[portNum]

Categories