gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-28 23:32:44 28 4
gpt4 key购买 nike

我正在 Linux 机器(AMD 6 核,16 GB RAM)上使用 JVM(Oracle 1.7 64 位),以了解应用程序中的线程数如何影响性能。我希望测量上下文切换在什么时候会降低性能。

我创建了一个创建线程执行池的小应用程序:

Executors.newFixedThreadPool(numThreads)

我每次运行程序都会调整numThreads,看看效果。

然后我将 numThread 个作业(java.util.concurrent.Callable 的实例)提交到池中。每一个都增加一个AtomicInteger,做一些工作(创建一个随机整数数组并将其打乱),然后 hibernate 一段时间。这个想法是模拟 Web 服务调用。最后,作业将自身重新提交到池中,因此我始终有 numThreads 个作业工作。

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

有了几千个线程,我每分钟可以处理多达 400,000 个作业。超过 8000 个线程,结果开始变化很大,这表明上下文切换正在成为一个问题。但是我可以继续将线程数增加到 30,000,并且仍然可以获得更高的吞吐量(每分钟 420,000 到 570,000 个作业)。

现在的问题是:我得到一个 java.lang.OutOfMemoryError: Unable to create new native thread 有超过 31,000 个作业。我试过设置 -Xmx6000M 这没有帮助。我试过玩 -Xss 但这也无济于事。

我读到 ulimit 可能很有用,但随着 ulimit -u 64000 的增加并没有改变任何东西。

信息:

[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) 上下文切换是可测量的,并显示在响应时间中。

这里有趣的是,在调整应用程序时,您可能会选择可接受的响应时间,例如 400 毫秒,并增加线程数,直到您获得该响应时间,在这种情况下,这将使应用程序处理大约 95一分钟一千个请求。

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

最佳答案

I get a java.lang.OutOfMemoryError: Unable to create new native thread with more than about 31,000 jobs. I have tried setting -Xmx6000M which doesn't help. I tried playing with -Xss but that doesn't help either.

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

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

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

  • 这样就剩下内存资源了。一次 1Mb 的 30,000 个线程约为 30Gb,这比您拥有的物理内存多得多。我的猜测是 30Gb 的虚拟内存有足够的交换空间,但是您将边界推得太远了。

-Xss 设置应该会有所帮助,但您需要使请求的堆栈大小小于默认大小 1m。此外,还有一个硬性的最小尺寸。

Question #1: What do I have to do to be able to create a bigger thread pool?

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

Question #2: At what stage should I expect to see context switching really reducing throughput and causing the process to grind to a halt?

这是无法预测的。这将高度依赖于线程实际在做什么。事实上,我认为您的基准测试不会给您答案,告诉您真正的多线程应用程序将如何运行。


Oracle 网站显示 this关于线程堆栈空间的话题:

In Java SE 6, the default on Sparc is 512k in the 32-bit VM, and 1024k in the 64-bit VM. On x86 Solaris/Linux it is 320k in the 32-bit VM and 1024k in the 64-bit VM.

On Windows, the default thread stack size is read from the binary (java.exe). As of Java SE 6, this value is 320k in the 32-bit VM and 1024k in the 64-bit VM.

You can reduce your stack size by running with the -Xss option. For example:

  java -server -Xss64k

Note that on some versions of Windows, the OS may round up thread stack sizes using very coarse granularity. If the requested size is less than the default size by 1K or more, the stack size is rounded up to the default; otherwise, the stack size is rounded up to a multiple of 1 MB.

64k is the least amount of stack space allowed per thread.

关于java - 具有数千个线程的内存设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14545924/

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