我正在尝试在OOME发生时重启进程。使用两个shell脚本启动Java二进制文件,其中一个导入其他脚本。我对第一个没有任何控制权,但可以根据需要修改第二个。 这是我正在尝试做的原型:
第一个shell脚本test.sh:
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Xmx10m"
. test1.sh
echo $JAVA_OPTS
java $JAVA_OPTS $es_params TestMemory
第二个shell脚本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\""
通常它的作用是JAVA_OPTS在test1.sh中构建,然后用于运行Java二进制文件,它只是在pidfile中写入PID然后创建OOME。
执行期间出现问题,java无法理解什么是参数以及什么是要运行的类。我认为这可能是引用的问题,我尝试了不同的方法来逃避JAVA_OPTS,但没有任何结果。我要么:
Unrecognized option: -9
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
或者
Error: Could not find or load main class "-XX:OnOutOfMemoryError=kill
如果我只取一个JAVA_OPTS的值并将其手动放在test.sh中,它就会完美运行。 任何想法如何更改test1.sh以使其工作?我想我几乎尝试了双重和单引号的所有可能方式,但没有任何成功。此外,如果我将restart_command放在restart.sh文件中并使用它而不是变量,它可以正常工作。
在运行set -x之后,我看到shell将每个空格字符修改为'' - 两侧添加'。转义不会产生任何结果。知道怎么避免这个吗?所以最后的赞扬是:
+ java -Xmx10m '"-XX:OnOutOfMemoryError=kill' '$(cat' 'test.pid);sleep' '2;/Users/davidt/test/TestMemory/bin/test.sh' '")' -Des.pidfile=test.pid TestMemory
我可以成功运行简化命令
java "-XX:OnOutOfMemoryError=echo 'Ups'" $es_params TestMemory
但这似乎是一个普遍的问题,shell只是讨厌变量空间我想:
JAVA_OPTS="\"-XX:OnOutOfMemoryError=echo 'Ups'\""
set -x
java $JAVA_OPTS TestMemory
此脚本失败,最后一行解释为:
java '"-XX:OnOutOfMemoryError=echo' ''\''Ups'\''"' TestMemory
我尝试了不同的选项来逃避
答案 0 :(得分:2)
这是一个shell问题。根据证据,我说当你不想要/不需要这个时候,贝壳会解释其中一个;
字符......以及可能是空间......发生。
如果在运行尝试启动JVM的命令之前在shell中运行set -x
,您将看到正在使用的实际命令。
似乎shell将每个空间翻译为' ',
不完全是。 shell将单引号插入到set -x
的输出中。它们只是指示参数边界的位置。它们并不存在......并且它们当然不会被传递给java
命令。
知道如何[a]取消它吗?
您需要做的是从您尝试执行的(最终)命令开始......
java -Xmx10m -XX:OnOutOfMemoryError="kill NNNN;sleep 2;/Users/davidt/test/TestMemory/bin/test.sh" -Des.pidfile=test.pid TestMemory
...并向后工作,以便shell变量,扩展和转义为您提供所需。
另外需要注意的是:
java -Xmx10m -XX:OnOutOfMemoryError="kill $(cat test.pid); ..."
可能不会工作。 kill $(cat test.pid)
命令使用shell语法,并且需要shell功能来插入PID文件的内容。我怀疑JVM将会知道如何处理它。 (或者更准确地说。它会按照字面意思告诉它去做,但那不是你想要的......)
如果您确实需要在运行“重启”命令时插入pid文件内容,那么建议您将restart命令转换为独立的shell脚本,并设置文件模式以使其可执行。工作起来会更简单,也更容易。
作为一般建议,使用shell脚本过于聪明是一个坏主意。变量扩展和命令解析的确切语义相当棘手,很容易让自己感到困惑......如果你想在多个层次上做这个。
答案 1 :(得分:1)
我最终将我想要执行的脚本放在一个单独的文件中,并将其作为参数提供给JVM,以便在OOME发生时执行。
echo "echo 'UPS'" >> oome_happened.sh
JAVA_OPTS="\"-XX:OnOutOfMemoryError='oome_happened.sh'\""
set -x
java $JAVA_OPTS TestMemory
答案 2 :(得分:0)
就像@DaTval说的那样,您应该将命令放在脚本中。脚本应该像这样。
#!/bin/bash
kill -9 $PPID
杀死脚本的调用者。