首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Java下减慢进程创建速度?

在Java下减慢进程创建速度?
EN

Stack Overflow用户
提问于 2011-01-01 03:23:59
回答 4查看 2.2K关注 0票数 4

我有一个大型堆(最高可达240 on,但在此执行阶段的大部分时间内都在20-40 on范围内)JVM1在具有24个内核的服务器上运行在Linux2下。我们有数以万计的对象必须由外部可执行文件处理&然后将这些可执行文件创建的数据加载回JVM。每个可执行文件产生大约0.5兆字节的数据(在磁盘上),当读入时,进程完成后,当然,更大。

我们的第一个实现是让每个可执行文件只处理一个对象。这涉及到产生的可执行文件数量是我们拥有对象的两倍(因为我们调用了一个调用可执行文件的shell脚本)。我们的CPU利用率一开始会很高,但不一定是100%,然后慢慢恶化。当我们开始测量以查看正在发生的事情时,我们注意到进程创建时间3持续变慢。虽然开始的时间是亚秒级,但最终会增长到一分钟或更长时间。由可执行文件完成的实际处理通常不到10秒。

接下来,我们更改了可执行文件,以获取要处理的对象列表,以尝试减少创建的进程数量。当批处理大小为几百个(约为当前样本大小的1%)时,进程创建时间从大约2秒开始,然后增长到大约5-6秒。

基本上,为什么随着执行的继续,创建这些进程需要这么长的时间?

1个Oracle JDK 1.6.0_22

2 Red Hat Enterprise Linux Advanced Platform 5.3,Linux内核2.6.18-194.26.1.el5 #1 SMP

3创建ProcessBuilder对象,重定向错误流并启动它。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-01-01 23:45:37

我的猜测是,如果Java使用fork/exec系统调用来生成子进程,那么您可能会遇到fork/exec的问题。

通常情况下,fork/exec是相当有效的,因为fork()做的非常少-所有页面都是写时复制的。对于非常大的进程(即映射了千兆字节页面的进程),这一点就不再适用了,因为页表本身需要相对较长的时间来创建-当然,还需要销毁,因为您立即调用了exec。

由于您正在使用大量的堆,这可能会影响到您。你映射的页面越多,它可能会变得越糟糕,这可能是导致渐进式减速的原因。

考虑以下两种情况之一:

使用posix_spawn的

  • ,如果这不是由libc
  • 中的fork/exec实现的,那么使用一个负责创建/收获其他进程的子进程;生成一次这个进程,并使用一些IPC (管道等)来告诉它该做什么。

注:这都是猜测;您可能应该做一些实验,看看情况是否如此。

票数 3
EN

Stack Overflow用户

发布于 2011-01-01 03:31:46

最有可能的情况是,您的资源即将耗尽。当您创建这些进程时,您的磁盘是否变得更加繁忙。你是否确保你拥有的进程少于你拥有的核心?(最小化上下文切换)您的平均负载是否低于24?

如果您的CPU消耗正在下降,您可能会遇到IO (磁盘/网络)争用,即进程无法以足够快的速度获取/写入数据以使其保持忙碌。如果您有24核,那么您有多少个磁盘?

我建议您为每个CPU设置一个进程(在您的情况下,我想是4个),为每个JVM分配6个并发运行的任务,以便在不使系统过载的情况下使用其所有核心。

票数 1
EN

Stack Overflow用户

发布于 2011-01-02 00:34:08

您最好使用一组长期存在的进程,将数据从队列中提取出来,并将它们发送回来,为每个事件不断派生新的进程,特别是从具有巨大堆的主机JVM中。

派生240 of的映像不是免费的,它会消耗大量的虚拟资源,即使只有一秒钟。操作系统不知道新进程将感知多长时间,因此它必须准备好,就好像整个进程将长期存在一样,因此在使用exec调用清除它之前,它设置了全部240 of的虚拟克隆。

相反,如果您有一个长期存在的进程,您可以通过某种队列机制( Java和C等都有许多队列机制)结束对象,这将减轻您派生进程的一些压力。

我不知道您是如何将数据从JVM传输到外部程序的。但是,如果您的外部程序可以使用stdin/stdout,那么(假设您使用的是unix),您可以利用inetd。在这里,您可以在inetd配置文件中为您的进程创建一个简单的条目,并为其分配一个端口。然后打开一个套接字,将数据倒入套接字,然后从套接字读回数据。Inetd为您处理网络细节,您的程序就像使用stdin和stdout一样简单。请注意,网络上将有一个开放的套接字,这在您的部署中可能是安全的,也可能是不安全的。但是,即使将遗留代码设置为通过网络服务运行,也是相当琐碎的。

您可以使用如下所示的简单包装器:

代码语言:javascript
复制
#!/bin/sh
infile=/tmp/$$.in
outfile=/tmp/$$.out

cat > $infile
/usr/local/bin/process -input $infile -output $outfile
cat $outfile
rm $infile $outfile

它不是这个星球上性能最高的服务器,但它肯定比一遍又一遍地分叉240 on要快得多。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4571928

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档