gpt4 book ai didi

solaris - Runtime.exec 导致重复的 JVM 无限期挂起直至被杀死 (Solaris 10)

转载 作者:行者123 更新时间:2023-12-02 10:54:50 27 4
gpt4 key购买 nike

全部,

我们正在 WebLogic 服务器 9.2 MP2 上运行 J2EE 应用程序,并在 Solaris 10 上使用 jrockit 64 位 JVM (27.3.1)。

我们调用useruntime.exec来调用一个名为jfmerge的可执行文件来创建PDF文档。

我们发现,在 Solaris 中,当调用 runtime.exec 时,会临时生成一个重复的 JVM 以启动 jfmerge 进程。虽然这效率很低(我们的 JVM 是 5 GB,因此重复的 shell JVM 也是 5 GB),但主要问题在于,当我们的应用程序中此功能(PDF 生成)负载很重时,有时重复的 JVM永远不会退出。

当 JVM 挂起时,服务器会产生大问题(应用程序极度缓慢和终止用户 session ),因为整个重复的 JVM 将其所有 5 GB 进程大小写入磁盘交换。

我们注意到以下挂起线程与挂起的 JVM 进程相关,直到该进程被手动终止:

"[STUCK] ExecuteThread: '17' for queue: 'weblogic.kernel.Default (self-tuning)'" id=3463 idx=0x158 tid=3460 prio=1 alive, in native, daemon at jrockit/io/FileNativeIO.readBytesPinned(Ljava/io/FileDescriptor;[BII)I(Native Method) at jrockit/io/FileNativeIO.readBytes(FileNativeIO.java:30) at java/io/FileInputStream.readBytes([BII)I(FileInputStream.java) at java/io/FileInputStream.read(FileInputStream.java:194) at java/lang/UNIXProcess$DeferredCloseInputStream.read(UNIXProcess.java:227) at java/io/BufferedInputStream.fill(BufferedInputStream.java:218) at java/io/BufferedInputStream.read(BufferedInputStream.java:235) ^-- Holding lock: java/io/BufferedInputStream@0xfffffffec6510470[thin lock] at gov/v3/common/formgeneration/sessionbean/FormsBean.getProcessStatus(FormsBean.java:809) at gov/v3/common/formgeneration/sessionbean/FormsBean.createPDF(FormsBean.java:750) at gov/v3/common/formgeneration/sessionbean/FormsBean.getTemplateDetails(FormsBean.java:450) at gov/v3/common/formgeneration/sessionbean/FormsBean.generateSinglePDF(FormsBean.java:1371) at gov/v3/common/formgeneration/sessionbean/FormsBean.generatePDF(FormsBean.java:263) at gov/v3/common/formgeneration/sessionbean/FormsBean.endorseDocument(FormsBean.java:2377) at gov/v3/common/formgeneration/sessionbean/Forms_qaco28_EOImpl.endorseDocument(Forms_qaco28_EOImpl.java:214) at gov/v3/delegates/common/FormsAndNoticesDelegate.endorseDocument(FormsAndNoticesDelegate.java:128) at gov/v3/actions/common/EndorseDocumentAction.executeRequest(EndorseDocumentAction.java:68) at gov/v3/fwk/controller/struts/action/V3CommonDispatchAction.dispatchToExecuteMethod(V3CommonDispatchAction.java:532) at gov/v3/fwk/controller/struts/action/V3CommonDispatchAction.executeBaseAction(V3CommonDispatchAction.java:336) at gov/v3/fwk/controller/struts/action/V3BaseDispatchAction.execute(V3BaseDispatchAction.java:69) at org/apache/struts/action/RequestProcessor.processActionPerform(RequestProcessor.java:484) at gov/v3/fwk/controller/struts/requestprocessor/V3TilesRequestProcessor.processActionPerform(V3TilesRequestProcessor.java:384) at org/apache/struts/action/RequestProcessor.process(RequestProcessor.java:274) at org/apache/struts/action/ActionServlet.process(ActionServlet.java:1482) at org/apache/struts/action/ActionServlet.doGet(ActionServlet.java:507) at gov/v3/fwk/controller/struts/servlet/V3ControllerServlet.doGet(V3ControllerServlet.java:110) at javax/servlet/http/HttpServlet.service(HttpServlet.java:743) at javax/servlet/http/HttpServlet.service(HttpServlet.java:856) at weblogic/servlet/internal/StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227) at weblogic/servlet/internal/StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125) at weblogic/servlet/internal/ServletStubImpl.execute(ServletStubImpl.java:283) at weblogic/servlet/internal/ServletStubImpl.execute(ServletStubImpl.java:175) at weblogic/servlet/internal/WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3231) at weblogic/security/acl/internal/AuthenticatedSubject.doAs(AuthenticatedSubject.java:321) at weblogic/security/service/SecurityManager.runAs(SecurityManager.java:121) at weblogic/servlet/internal/WebAppServletContext.securedExecute(WebAppServletContext.java:2002) at weblogic/servlet/internal/WebAppServletContext.execute(WebAppServletContext.java:1908) at weblogic/servlet/internal/ServletRequestImpl.run(ServletRequestImpl.java:1362) at weblogic/work/ExecuteThread.execute(ExecuteThread.java:209) at weblogic/work/ExecuteThread.run(ExecuteThread.java:181) at jrockit/vm/RNI.c2java(JJJJJ)V(Native Method) -- end of trace

我们想做几件事:

1.) 防止生成重复的 JVM,因为在执行简单的 jfmerge 可执行文件时我们不需要它的任何函数,并且它会产生大量开销。

2.) 在短期内至少可以防止这个重复的 JVM 无限期地处理。

最佳答案

这个答案来晚了,但我们也有同样的问题,而我们的问题是 Solaris 如何管理内存。

问题是当我们有一个应用程序服务器时,在我的例子中使用大量内存 10GB,并且我们想要运行一个简单的“ls”,新进程需要 10GB 才能运行。

Solaris 需要我们的服务器有 10GB 的额外可用空间,Linux 使用称为“写时复制”的功能,此功能减少了 fork 新进程的开销

http://developers.sun.com/solaris/articles/subprocess/subprocess.html

历史背景和问题描述

传统上,Unix 只有一种方法来创建新进程:使用 fork() 系统调用,通常后跟 exec() 系统调用。 fork() 调用会复制整个父进程的地址空间,然后 exec() 将该副本转换为新进程。

(注意:在 Solaris 操作系统中,术语交换空间用于描述为系统配置的物理内存和磁盘交换空间的组合。但是,对于其他 Unix 系统,该术语可能意味着磁盘上的交换空间,也称为作为后备存储。为了避免任何混淆,我将使用术语虚拟内存 (VM) 来表示物理内存加磁盘交换空间。)

一般来说,fork/exec 方法效果很好。但是,它在某些情况下也有缺点,例如无缘无故地耗尽内存以及 fork 性能较差。

内存不足:对于大内存进程,fork()系统调用可能会由于VM数量不足而失败,因为fork()需要两倍于父内存的内存量。即使 fork() 紧随其后的是 exec() 调用(这将释放大部分额外内存),这种情况也可能发生。发生这种情况时,应用程序通常会终止。

例如,假设 64 位应用程序当前消耗 6 GB 的 VM,并且需要创建一个子进程来运行 ls(1) 命令。父进程发出 fork() 调用,仅当此时还有另外 6 GB 的 VM 可用时,该调用才会成功。如果系统没有那么多可用的 VM(这是一种常见情况),fork() 将失败并出现 ENOMEM。显然,ls(1) 命令不需要接近 6 GB 的内存来运行,但 fork() 不知道这一点。

不仅是应用程序,Sun 自己的工具也可能遇到同样的问题。例如,已针对 dbx 提交以下 Sun RFE(增强请求):“4748951 dbx shell 应使用 posix_spawn() 执行非内置命令,而不是 fork(2)”。

RFE 4748951 是在客户的实用程序调用 dbx 来使用脚本读取巨大的核心文件时出现的,该脚本还需要从 dbx 中运行 cut(1) 命令。他们收到无法 fork - 重试错误消息,导致 dbx 中止。调查显示 dbx 使用 fork/exec 执行微小的 cut(1) 命令,并在 fork() 调用期间耗尽了 VM。

Solaris Java 虚拟机 (JVM) 目前也遇到同样的问题,如 Sun RFE 中所述:“5049299 在 S10 上使用 posix_spawn,而不是 fork,以避免交换耗尽”。

<小时/>

所以你有3个选择。

1.- 提前执行 Runtime.exec 函数。

2.- 创建与其他java服务器的进程间通信,并在那里执行Runtime.exec指令。

3.- 创建 JNI 类来调用系统 C 函数。我选择了这个选项,效果非常好。

我将示例代码放在这里。

Java 代码。

public class CallOS {
static {
System.loadLibrary("CallOS");
}

public native int exec(java.lang.String cmd);

public static void main(String[] args) {
int returnValue = 0;
returnValue = new CallOS().exec("ls -la");
System.out.println("- " + returnValue);
}
}

C 头代码。这是用 javah -jni CallOS 生成的

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CallOS */

#ifndef _Included_CallOS
#define _Included_CallOS
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: CallOS
* Method: exec
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_CallOS_exec
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

C 代码。

#include "CallOS.h"
#include <stdlib.h>

JNIEXPORT jint JNICALL Java_CallOS_exec
(JNIEnv *env, jobject obj, jstring cmd)
{
jint retval;
jbyte *str;

str = (*env)->GetStringUTFChars(env, cmd, NULL);
if(str == NULL) return NULL;

retval = system(str);

(*env)->ReleaseStringUTFChars(env, cmd, str);
return retval;
};

希望这对您有帮助。

关于solaris - Runtime.exec 导致重复的 JVM 无限期挂起直至被杀死 (Solaris 10),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1160656/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com