当前位置: 首页 > 知识库问答 >
问题:

具有数千个线程的内存设置

南门正业
2023-03-14
Executors.newFixedThreadPool(numThreads)

每次运行程序时,我都会调整numthreads,以查看它的效果。

然后,我将NumThread作业(java.util.concurrent.Callable的实例)提交到池。每一个都增加一个AtomicInteger,做一些工作(创建一个随机整数数组并对其进行洗牌),然后Hibernate一段时间。其思想是模拟一个web服务调用。最后,作业将自己重新提交到池中,这样我总是有numthreads作业在工作。

我正在测量吞吐量,例如每分钟处理的作业数。

现在的问题是:我得到了一个java.lang.OutOfMemoryError:无法创建新的本机线程,作业超过了31,000个。我尝试过设置-xmx6000m,但这没有帮助。我尝试使用-xss,但这也没有帮助。

我读到过ulimit可能很有用,但是使用ulimit-u64000增加值并没有改变任何东西。

有关信息:

[root@apollo ant]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 127557
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) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

那么问题1:我必须做什么才能创建一个更大的线程池

问题2:我应该在什么阶段看到上下文切换真的会降低吞吐量,并导致进程陷入停顿?

以下是一些结果,我修改了它,做了一点更多的处理(正如建议的那样),并开始记录平均响应时间(正如建议的那样)。

// ( (n_cores x t_request) / (t_request - t_wait) ) + 1
// 300 ms wait, 10ms work, roughly 310ms per job => ideal response time, 310ms
// ideal num threads = 1860 / 10 + 1 = 187 threads
//
// results:
//
//   100 =>  19,000 thruput,  312ms response, cpu < 50%
//   150 =>  28,500 thruput,  314ms response, cpu 50%
//   180 =>  34,000 thruput,  318ms response, cpu 60%
//   190 =>  35,800 thruput,  317ms response, cpu 65%
//   200 =>  37,800 thruput,  319ms response, cpu 70%
//   230 =>  42,900 thruput,  321ms response, cpu 80%
//   270 =>  50,000 thruput,  324ms response, cpu 80%
//   350 =>  64,000 thruput,  329ms response, cpu 90%
//   400 =>  72,000 thruput,  335ms response, cpu >90%
//   500 =>  87,500 thruput,  343ms response, cpu >95%
//   700 => 100,000 thruput,  430ms response, cpu >99%
//  1000 => 100,000 thruput,  600ms response, cpu >99%
//  2000 => 105,000 thruput, 1100ms response, cpu >99%
//  5000 => 131,000 thruput, 1600ms response, cpu >99%
// 10000 => 131,000 thruput, 2700ms response, cpu >99%,  16GB Virtual size
// 20000 => 140,000 thruput, 4000ms response, cpu >99%,  27GB Virtual size
// 30000 => 133,000 thruput, 2800ms response, cpu >99%,  37GB Virtual size
// 40000 =>       - thruput,    -ms response, cpu >99%, >39GB Virtual size => java.lang.OutOfMemoryError: unable to create new native thread

我把它们解释为:

1)尽管应用程序在96.7%的时间内处于Hibernate状态,但仍然需要进行大量的线程切换。2)上下文切换是可测量的,并显示在响应时间中。

这里有趣的是,当调优应用程序时,您可能会选择可接受的响应时间,比如400ms,并增加线程数,直到您获得该响应时间为止,在本例中,该响应时间将使应用程序每分钟处理大约9万5千个请求。

经常有人说,理想的线程数是在核心数附近。在有等待时间(阻塞线程,例如等待数据库或web服务响应)的应用程序中,计算需要考虑这一点(参见上面的公式)。但即使是理论上的理想也不是实际的理想,当你观察结果或调整到特定的响应时间时。

共有1个答案

廉高邈
2023-03-14

我得到一个java.lang.OutOfMemoryError:无法使用超过31,000个作业创建新的本机线程。我试过设置-xmx6000m,这没有帮助。我试着玩-xss,但这也没有帮助。

-xmx设置不会有帮助,因为线程堆栈不是从堆中分配的。

正在发生的情况是,JVM正在向OS请求内存段(在堆之外!)以保存堆栈,而操作系统拒绝该请求。最可能的原因是ulimit或OS内存资源问题:

>

  • 数据序列大小”ulimit是无限的,所以这不应该是问题所在。

    这样就会留下内存资源。30,000个线程,每次1MB,相当于30GB,这比您拥有的物理内存多得多。我的猜测是30GB的虚拟内存有足够的交换空间,但您把边界推得有点过了。

    -xss设置应该有所帮助,但您需要使请求的堆栈大小小于1M的默认大小。此外还有一个严格的最小尺寸。

    问题#1:我必须做什么才能创建一个更大的线程池?

    将默认堆栈大小减小到当前值以下,或增加可用虚拟内存量。(不推荐使用后者,因为看起来您已经严重过度分配了。)

    问题2:我应该在什么阶段看到上下文切换真的会降低吞吐量,并导致进程陷入停顿?

    Oracle站点关于线程堆栈空间的主题是这样说的:

    在Java SE 6中,Sparc上的默认值在32位VM中为512K,在64位VM中为1024K。在x86 Solaris/Linux上,32位VM中为320K,64位VM中为1024K。

    在Windows上,默认的线程堆栈大小是从二进制(java.exe)中读取的。在Java SE 6中,该值在32位VM中为320K,在64位VM中为1024K。

    可以通过使用-xss选项运行来减小堆栈大小。例如:

      java -server -Xss64k
    

    请注意,在Windows的某些版本上,OS可能使用非常粗略的粒度将线程堆栈大小取整。如果请求的大小比默认大小小1K或更多,则堆栈大小四舍五入为默认大小;否则,堆栈大小将四舍五入为1 MB的倍数。

    64K是每个线程允许的最少堆栈空间量。

  •  类似资料:
    • 问题内容: 在Java中拥有多个线程池的优缺点是什么?我已经看过代码,其中有多个线程池用于不同的“类型”任务,而且我不确定它是更好的设计还是只是开发人员感到懒惰。一个示例是将ScheduledThreadPoolExecutor用于定期执行的任务或具有超时的任务,而将另一ThreadPoolExecutor用于其他任务。 问题答案: 具有单独的专用线程池的目的是,使活动不会因线程不足而被饥饿,因为

    • 问题内容: Go 支持以数千个逗号输出数字吗? 输出,我可以指定输出什么格式呢? 这些文档似乎没有提到逗号,而且我也无法立即在源代码中看到任何内容。 问题答案: fmt打印动词均不支持数千个分隔符。

    • 我使用Netty 4创建了一个相当直接的服务器。我已经能够将它扩展到处理数千个连接,而且它从未超过40个线程。 为了测试它,我还创建了一个创建数千个连接的测试客户端。不幸的是,这会创建和连接一样多的线程。我希望尽量减少客户端的线程。我已经看了很多帖子。许多示例显示了单个连接设置。这个和这个说在客户端之间共享NioEventLoopGroup,我这样做了。我得到的nioEventLoopGroup数

    • 我正在使用matplotlib的hist()函数或bar()制作直方图,我想使用 我尝试过使用rwidth()并改变其值,也尝试过使用figsize()并简单地扩展绘图的大小,但最终的结果总是每个垂直条彼此相邻,中间没有空格。

    • 问题内容: 我们正在构建一个eLearningMultipleChoice工具,成千上万的用户将完成我们的测试。我们已经有成千上万的其他研讨会的订阅者,因此很可能成千上万的人也将完成MC测试。 现在,我们需要跟踪每个用户回答的每个问题,花了他多长时间,是否正确(经过多次尝试之后),如果不是,他给出了哪个错误答案等等。确实有很多数据。 现在,我们将有成千上万的问题和成千上万的用户。由于每个问题至少要

    • 问题内容: 当我们在程序中启动线程时,是否有任何方法可以为每个线程分配内存限制? 我的意思是我们为新流程分配了以下内容: 我们可以用Java线程做任何类似的事情吗? 基本上,我的每个线程都将执行某项任务,我希望对每个线程的内存使用量设置一些最大限制。 问题答案: 我们可以用Java线程做任何类似的事情吗? 不能。进程中的线程通常用于访问进程(在本例中为JVM)中的共享主内存。 基本上,我的每个线程