4

我租了一个小型 tomcat 服务器,通过dailyRazor 上的jsp 为android 应用程序提供http-get 服务。最大 Java 堆是“最大内存:92.81 MB”。

maxThreads 的默认 tomcat 设置为 25。随着使用我的服务的用户数量的增加,我在黄金时段收到很多服务器拒绝连接/超时(我认为这是因为线程池太小)。这就是我将 maxThreads 增加到 250 的原因。在这个晚上,服务器崩溃了,显示了多个 java.lang.OutOfMemoryError 。对于小堆来说,250 似乎有点重:p 我暂时将 maxThreads 减少到 50,这似乎很好,因为我没有得到任何错误。

由于我对tomcat知之甚少,因此我想寻求一种为maxThreads找到正确数字的好方法。我考虑过查看一个线程的最大内存使用量。然后 maxThreads = (maxMemory / memoryOfOneThread)。有更好的解决方案吗?

谢谢danijoo

4

3 回答 3

3

每个线程使用的内存量取决于您在线程中执行的操作。所以这取决于你的软件。

没那么容易计算。

但是 92MB 对于一个 tomcat 来说,是非常紧张的。我会想办法解决这个问题。

于 2013-07-01T10:03:52.837 回答
0

您应该在公式中添加堆栈大小。它取决于 JVM,例如,对于 HotSpot,32 位 JVM 上每个线程的默认堆栈大小约为 512k。顺便说一句,像你说的这么小的内存量和 250 个线程堆栈大小可能是实际问题。请注意,您可以使用-Xss选项更改它。

于 2013-07-01T10:36:12.630 回答
0

答案是没有好办法,AFAIK。或者更准确地说,没有什么比“试试看”更好的了。


但我回答的真正原因是指出您对问题的理解和期望中的一些缺陷。

  1. 线程不使用堆内存。或者至少不是直接的。

    线程的大部分内存使用是线程堆栈。线程堆栈大小是可调的,并且具有特定于平台的默认值,可以高达 1Mb。

    但是...线程堆栈未在 Java 堆中分配。它分配在堆外内存中。

  2. 如果您的系统在您增加堆栈数量时由于 OOME 而崩溃,那么堆使用量是由于在线程上运行的代码,而不是线程本身。(好吧,你可能知道。)

  3. 如果您遇到请求被丢弃等问题,那么增加线程数通常不是解决方案。事实上,它很可能会使吞吐量变得更糟。


问题是,要执行线程,必须将其分配给处理器;即“核心”。您的 Tomcat 服务器可能有 2 个或 4 个内核(我猜)。这意味着任何时候只能执行 2 或 4 个线程。有 25 个线程,这意味着当所有 25 个线程都处于活动状态时,它们将获得大约 1/6 的核心 CPU 时间。如果有 250 个线程处于活动状态(如果曾经发生过),它们将获得 1/60 的核心。同时:

  • 这些请求中的每一个都将创建一堆对象,这些对象在请求完成之前不能被垃圾收集。

  • 这些请求中的每一个都可能竞争数据库周期、磁盘 I/O 带宽、网络带宽等。

  • 根据应用程序的性质,数据结构/数据库行的争用可能会增加,从而导致线程上下文切换开销增加。

会有一个最佳点,线程数可以为您提供最佳的请求吞吐量。如果您大大超过了这一点,吞吐量(每秒完成的请求数)将会下降,并且处理每个请求的平均时间将会增加。走得太远,系统就会停止运转。(OOME 是这种情况发生的一种方式。另一种是请求花费了很长时间,以至于客户端超时并停止等待响应。)

基本上,您的应用程序(经过优化调整)将达到一定的平均吞吐率。如果您的实际请求率超过此值,那么最好的策略是处理您可以处理的请求,并迅速放弃其余的请求。丢弃请求可能看起来很糟糕,但它比需要很长时间才能响应以使请求者超时并启动新请求的替代方案要好。

于 2013-07-01T12:08:26.260 回答