我租了一个虚拟机,运行的是 Ubuntu 9.04。我安装了 SUN JDK 6.0 (通过 apt-get) 和 Tomcat 6.0.18 (通过解压)。
Java 的常见问题(部分解决)
起初,由于内存问题,无法运行 JVM。即使是java -version
像
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.
我发现,尽管free
报告了 44 GB 的可用内存,但我只能使用其中的一小部分,大约每次分配 284 MB。运行java -Xms10m -Xmx256m -version
正常,但我不想更改每个调用 java 的脚本。
我还阅读了有关JAVA_OPTS
环境变量的信息,许多应用程序都支持该变量。我已将其设置为"-Xms10m -Xmx256m"
Tomcat 问题
tomcat 启动脚本catalina.sh
也使用了JAVA_OPTS
。但即便如此,我仍然会收到上面提到的三行错误,可在中读取logs/catalina.out
。我知道使用了 JAVA_OPTS,因为当我将无意义的内容放入该变量时,我会在中看到后果logs/catalina.out
。
看起来 Tomcat 还想启动 javac,而 javac 需要以-J
like为前缀的选项-J-Xms10m -J-Xmx256m
。但我不确定这是否与问题有关,因为除了这三行之外没有其他输出。
我正在通过 启动 Tomcat,bin/startup.sh
然后依次调用bin/catalina.sh
。我知道也可以通过 启动它jsrv
,但我无法做到这一点,因为 的 make / configure 过程jsrv
也需要调用 ,javac
这会失败并出现上面提到的众所周知的三行错误消息。
现在我对两种可能的解决方案感兴趣:
- 我怎样才能让 Java只是工作在我的虚拟主机上,无论谁呼叫
java
或javac
无论他如何呼叫? - 如果这是不可能的,我该如何调整 Tomcat 以使其运行?
PS:请注意,我只能控制虚拟机,但无法控制周围的物理机器,而且对其了解有限。
备注:抱歉,这个问题的标题太菜鸟了,但我觉得原来的标题写得很好,没有吸引足够的读者,所以我觉得这个标题可能会有帮助 ;) 它确实有帮助,因为我在第一个小时内没有获得任何浏览量,但在更改后的一个小时内获得了 8 次浏览量。奇怪的世界。
编辑:这是输出ulimit -a
:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 16382
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
答案1
javac
通常会产生一个单独的进程应该属于不同的流程规则。
-J
选项用于通过包装器/启动器将参数传递给 JVM,我还没有在 Tomcat 上看到过这个。
找出 -Xmx 的来源:
find /your/install/dir/with/tomcat |xargs grep '-Xmx'
答案2
尝试ulimit -v unlimited
在启动 tomcat 之前运行。如果可行,您可以将其添加到一个或两个启动脚本中,或者添加到/etc/profile
或~/.bashrc
其他某个 shell 配置文件脚本中。
答案3
由于没有其他选择,我尝试了一种肮脏的黑客方法:用 shell 脚本替换java
和javac
,以确保传递正确的参数并允许我查看准确的参数列表。由于这已经是一种非常具体的解决方案的尝试,而不是问题的一部分,所以我想把它放到答案中。
我搜索了java
文件系统中的所有出现。结果太多了,因为我的机器上有多个 JRE 和 JDK。即使删除了所有版本,只留下一个版本,仍然有很多。我过去常常find / -name "java" |xargs file
找出哪个是真实的一。它告诉我:
/var/lib/dpkg/alternatives/java: ASCII text
/etc/alternatives/java: symbolic link to `/usr/lib/jvm/java-6-sun/jre/bin/java'
/usr/share/java: directory
/usr/lib/jvm/java-6-sun-1.6.0.16/bin/java: symbolic link to `../jre/bin/java'
/usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/java: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.4.0, not stripped
/usr/bin/java: symbolic link to `/etc/alternatives/java'
所以我知道那/usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/java
是可执行文件。我将其重命名,javaexec
并将一个 shell 脚本放在其旧位置:
mv /usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/java /usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/javaexec
nano /usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/java
(see below for file contents)
chmod +x #!/bin/bash -e
这确保了java
对 的每次调用都指向我的脚本,该脚本将使用正确的参数调用可执行文件。之后,我对 做了类似的可怕事情javac
。我的脚本内容:
#!/bin/bash -e
line=""
for i in $*
do
if [[ "$i" == *Xmx* ]]; then
echo "Seen -Xmx and removed"
elif [[ "$i" == *MaxPerm* ]]; then
echo "Seen -XX:MaxPermSize and removed"
else
line="$line $i"
fi
done
exec="/usr/lib/jvm/java-6-sun-1.6.0.16/jre/bin/javaexec -Xms10m -Xmx100m $line"
echo Now executing $exec
$exec
-Xmx
它从命令行中删除涉及或类似的每个参数-XX:MaxPermSize
,并放入其自己的 -Xms 和 -Xmx 限制。
现在当我启动 Tomcat 时,它仍然会失败,但最终,JVM 启动了,执行了一些操作,然后退出并显示一条有意义的消息。虽然没有真正的成功,但它让我更加满意,因为从那时起,我知道该怎么做了。虽然 Tomcat 仍然无法运行,但它有一个很好的副作用:
现在我终于可以在命令行或脚本中调用java
或javac
,而且它们不会崩溃,这在以前是不可能的根本! 他们只是跑步!嘿,我觉得自己是文字之王,我终于让 Java 在一台拥有 44GB 内存的机器上运行,而不会抱怨内存不足。这确实是计算机历史上伟大的一天!
答案4
我曾经遇到过类似的问题。你可以尝试使用以下方式启动 Java
vm.overcommit_memory = 1 复制代码
在 /etc/sysctl.conf 中设置。或者简单地 echo"1" > /proc/sys/vm/overcommit_memory
或者使用 overcommit_memory、overcommit_ratio http://www.redhat.com/magazine/001nov04/features/vm/