I have a class that is being executed through a script in unix (Solaris 9). Inside of the script the class is being run like this:
java -cp $CLASSPATH myPackage.component.MyMainClass $PROPERTIES_PATH/myMainClassProperties.properties
That shell needs to be monitored in order to see whether it works correctly or it fails, and it also is going to be run parallel with a different parameter file. So, my questions are:
How can I know what class is being executed if I use top. Is that possible?**
Is there a way to uniquely identify the class so it doesn't crash when running parallel?
Will it always be shown as myPackage.component.MyMainClass in the table of processes?
When I say parallely, I refer to something like:
java -cp $CLASSPATH myPackage.component.MyMainClass $PROPERTIES_PATH/myMainClassProperties.properties
and in another window/session/job
java -cp $CLASSPATH myPackage.component.MyMainClass $PROPERTIES_PATH/mySomeOtherProperties.properties
**When I say so, is because top shows something like this:
PID USERNAME THR PRI NICE SIZE RES STATE TIME CPU COMMAND
8545 batman 47 4 10 190M 112M sleep 0:04:00 0.07% java
9022 joker 91 4 10 286M 211M sleep 0:01:00 0.09% java
You can let top tell you the complete command, that will include any arguments you pass to the VM.
Also ps will give you the complete command as well (with the matching arguments).
In my debian I can switch the displayed command with the c toggle (start top and hit c until it shows the whole command)
for ps I use the arguments -ef (but -f) alone should do for that situation.
You may want to read the output of man ps and man top
It was possible to get the info using ptree | grep java or ptree | grep MyMainClass
It lists a tree of the processes that are being executed as well as the command that is being runned in there for example:
13456 ksh
123476 java -cp java -cp /classpath/fullpath myPackage.component.MyMainClass /full/properties/path/myMainClassProperties.properties
The first line is a shell script, and inside it (next line) calls the java jar. This works for Solaris 9.
Thanks #Angelo-Neuschitzer for the heads up.
Related
I checked quite a lot of other answers for this question on SO, but none of them really seem to work consistently, and correctly. Also, the examples weren't fitting my use case.
I have a java application jar which has a main class. I want to run it with the following arguments:
-Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
I am always getting simply the following when I try to run it using the following command on my powershell script (not command line)
Start-Process java -ArgumentList '-Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005 the.jar.in.myClassPath.mainClass startArgs
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id SI ProcessName
------- ------ ----- ----- ----- ------ -- -- -----------
6 2 204 704 7 0.00 3588 1 java
My java home path is correctly set in environment variables so there's nothing wrong there.
I ran an echo of the argument set and they look correct. I am kind of stuck here to figure out why this causing a problem? Powershell is more complicated as opposed to DOS because when I run it in DOS Command Prompt, it just works. So what has gone wrong for me here?
Regards,
Why Start-Process? Just run the command, quoting the needed parameters. You should be able to just run it this way:
java -Xms1300m -Xmx1300m -classpath "myClassPath;anotherone;anotherOne" -Xdebug "-Djava.compiler=NONE" "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
Notes:
Quote the the argument for -classpath since it contains ; characters.
Quote -D and its attached argument because it contains the . character.
Quote -X and its attached argument because it contains , and = characters.
Basically: Quote a parameter that contains characters that are otherwise syntactically meaningful to PowerShell.
You can troubleshoot executable parameter passing using a handy program I wrote called showargs.exe, which you can get from downloading the code associated with the following article:
IT Pro Today - Running Executables in PowerShell
This is my exact batch file. I have tried to convert it doing some research online and get an error
"Failed to execute child process "/home/pi/Desktop/TeachVal/TeachValLinuxShell" (No such file or directory)
echo off
cls
echo Running TeachVAL II...
set path=%path%;/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/bin
java -classpath comm.jar;Robot.jar;TeachVAL TeachVAL
cls
exit
This one is my attempt at translating.
#!/bin/bash
set +v
clear
echo "Running TeachVAL II..."
java -cp ".dir1;dir2;path/home/pi/Desktop/TeachVAL/comm.jar;
path/home/pi/Desktop/TeachVAL/Robot.jar;/home/pi/Desktop/TeachVAL/TeachVAL"
clear
exit
Welcome to Linux--life is good here, but there are a few things that work slightly differently, when compared to Windows.
One difference is that Windows uses semicolon (;) to separate entries in a list of paths, but Linux uses colons (:) for that purpose.
So, the Windows command:
java -classpath comm.jar;Robot.jar;TeachVAL TeachVAL
would correspond to this on Linux:
java -classpath comm.jar:Robot.jar:TeachVAL TeachVAL
In general, on Linux, semicolons are used to put multiple command lines into a single line. Once you've learned that, I think you can then understand why:
java -cp .dir1;/home/pi/Desktop/TeachVAL/TeachVAL
would be the same as:
java -cp .dir1
/home/pi/Desktop/TeachVAL/TeachVAL
That would run java (with no class to be executed) and then try to run "/home/pi/Desktop/TeachVAL/TeachVAL" which can't be found.
There are many more differences to learn; here's a page that will help you get started: http://tldp.org/LDP/abs/html/dosbatch.html
I am running a minecraft server for my son, i'm new at minecraft servers, anyway it seems it keeps dying as it cant keep up? ok so its a VM and i will be assigning more resources to it at some point but my question is as follows
I initiate the server to load up via a script
bukkit.sh is the script an inside it has
#!/bin/bash
java -Xmx1024M -jar /minecraftserver/bukkitserver/craftbukkit-1.7.1.jar -o true
now at somepoint during the day or night it will die as it cant keep up, is there a way i can have some other script run alongside it and see that the process has died and to run that script again to start the server.
when i run top i can see that java is at the top using all the resources so im 100% thats the minecraft java. Does the PID stay the same each time it loads up?
Would be great if someone could let a hand on this ...
I assume the java process remains in the foreground once it's launched? Is there any reason you can't just do:
while :
do
java -Xmx1024M -jar /minecraftserver/bukkitserver/craftbukkit-1.7.1.jar -o true
done
Then any time the java exits, the script will simply restart it.
EDIT:
You could create a script, lets call it craftbukkit.sh
Make sure it is execute by using: chmod +x craftbukkit.sh
Then inside the script you would write:
#!/bin/sh
ps auxw | grep craftbukkit-1.7.1.jar| grep -v grep > /dev/null
if [ $? != 0 ]
then
/path/to/your/bukkit.sh
fi
Change /path/to/your/bukkit.sh to wherever that minecraft startup script is.
Then you need to add this script to your crontab, this is accomplished by entering the crontab editor: crontab -e
If you want the script to run every 5 minutes, add a line that looks like this:
*/5 * * * * /path/to/craftbukkit.sh
Note that you must change the /path/to to point to where you have created the craftbukkit.sh script.
I'm trying to restart process when OOME happens. Java binary is launched using two shell scripts, one of them imports other. I don't have any control of the first one but can modify the second one as I want.
This is a prototype what I'm trying to do:
First shell script test.sh:
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Xmx10m"
. test1.sh
echo $JAVA_OPTS
java $JAVA_OPTS $es_params TestMemory
Second shell script test1.sh:
#!/bin/sh
pidfile="test.pid"
touch $pidfile
params="$parms -Dpidfile=$pidfile"
kill_command="kill -9 \$(cat $pidfile)"
dir=$( cd $(dirname $0) ; pwd -P )
path="$dir/$(basename $0)"
start_command="$path $#"
restart_command="$kill_command;sleep 2;$start_command"
JAVA_OPTS="$JAVA_OPTS -XX:OnOutOfMemoryError=\"$restart_command\""
Generally what it does is JAVA_OPTS is constructed inside test1.sh and then used to run Java binary, which just writes PID in pidfile and then creates OOME.
Problem happens during execution, java can't understand what is a parameter and what is a class to run. I think it might be a problem of quoting, I tried different ways to escape JAVA_OPTS, but without any result. I'm either getting:
Unrecognized option: -9
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Or
Error: Could not find or load main class "-XX:OnOutOfMemoryError=kill
If I just take a value of JAVA_OPTS and put it manually in test.sh it runs perfectly.
Any ideas how can I change test1.sh to make it work? I think I tried almost every possible way of putting double and single quotes, but without any success. Also if I put restart_command in restart.sh file and use it instead of the variable, it works fine.
After running set -x I saw that shell modifies every single space character to ' ' - adds ' on both sides. Escaping doesn't gives any result. Any idea how to avoid this? So final commend is:
+ java -Xmx10m '"-XX:OnOutOfMemoryError=kill' '$(cat' 'test.pid);sleep' '2;/Users/davidt/test/TestMemory/bin/test.sh' '")' -Des.pidfile=test.pid TestMemory
Update
I can run simplified command successfully
java "-XX:OnOutOfMemoryError=echo 'Ups'" $es_params TestMemory
But it seems a general problem, shell just hates spaces into variables I guess:
JAVA_OPTS="\"-XX:OnOutOfMemoryError=echo 'Ups'\""
set -x
java $JAVA_OPTS TestMemory
This script fails and the last line is interpreted as:
java '"-XX:OnOutOfMemoryError=echo' ''\''Ups'\''"' TestMemory
I tried different options to escape
This is a shell problem. Based on the evidence, I'd say that one of the ; characters ... and possibly some why space ... is being interpretted by the shell when you don't want / need this to happen.
If you run set -x in the shell before running the command that is trying to start the JVM, you will see the actual command that is being used.
It seems shell translates every single space to ' ',
Not exactly. The single quotes are inserted by the shell into the output you are getting from set -x. They simply indicating where the argument boundaries are. They are not really there ... and they are certainly NOT being passed to the java command.
Any idea how to [a]void it?
What you need to do is start from the (final) command that you are trying execute ...
java -Xmx10m -XX:OnOutOfMemoryError="kill NNNN;sleep 2;/Users/davidt/test/TestMemory/bin/test.sh" -Des.pidfile=test.pid TestMemory
... and work backwards, so that the shell variables, expansions and escaping give you what you need.
The other thing to note is that this:
java -Xmx10m -XX:OnOutOfMemoryError="kill $(cat test.pid); ..."
probably won't work. The kill $(cat test.pid) command is using shell syntax and requires shell functionality to interpolate the contents of the PID file. I doubt that the JVM is going to know what to do with that. (Or more accurately. It will do what you have literally told it to do, but that will not be what you want ...)
If you really need to interpolate the pid file content when the restart command is run as you appear to be trying to do, then suggest that turn the restart command into a free-standing shell script, and set the file mode so that it is executable. It will be simpler and a lot easier to get working.
As a general piece of advice, is is a bad idea to be too clever with shell scripts. The exact semantics of variable expansion and command parsing are rather tricky, and it is easy to get yourself really confused ... if you are trying to do this at multiple levels.
I ended up put the script I wanted to execute in a separate file and gave it as a parameter to JVM to execute when OOME happens.
echo "echo 'UPS'" >> oome_happened.sh
JAVA_OPTS="\"-XX:OnOutOfMemoryError='oome_happened.sh'\""
set -x
java $JAVA_OPTS TestMemory
Like #DaTval said, you should put the command in a script. The script should be someting like.
#!/bin/bash
kill -9 $PPID
Kill the caller of scripts.
How can I get the details of a process in Linux. I want the total execution time, memory map of a process. In this context the process will be a simple Java program. I only know the file name, not the process id. Any help will be appreciated
If the process is not already running, then time will print total execution time. There is both a bash builtin and a standalone command of that name, with somewhat different behaviour. But as your mention of memory maps suggests an already running process, I'll concentrate on that.
You can find a process by executable using ps -C java. If you want to know what that java binary is running, you can do things like this to find the pid:
ps -C java -o pid,time,cmd | awk '/foo\.jar/{print $1,$2}' | \
while read pid time; do
echo "PID $pid, TIME $time"
cat /proc/$pid/maps
echo ""
done
If you don't like the output format, replace the loop with something else.
Here is what this does:
-C java: Find java processes
-o pid,time,cmd: Print these fields
/foo\.jar/: Only take lines containing that regular expression
print $1,$2: Print pid and time columns
/proc/$pid/maps: Access proc file conatining the memory map
If you know only the program name, and not the process id, you first have to find out which processes (they can be many of them) are running that program.
You could use e.g. some of the below commands to find out, assuming the program name is progname:
ps auxw | grep progname
pidof progname
pgrep progname
(notice that if you are using a JVM to run some Java program the progname is always java which does not help much)
You might also use top or htop
Once you got an interesting pid, e.g. 1234, you could get more information about that process with e.g.:
ps -lw 1234
cat /proc/1234/status
cat /proc/1234/stat
cat /proc/1234/stack
cat /proc/1234/maps
cat /proc/1234/smaps
Look also in other files and directories of /proc/1234/ such as /proc/1234/fd/ and others.
The Linux kernel is telling information about processes thru /proc so you should learn more about it.
I'm planning to use some memory profiling tools such as valgrid.