【发布时间】:2019-08-29 21:07:09
【问题描述】:
我使用 Java 实现了一个非常简单的 Thrift 服务器。
SimpleServer.java
public class SimpleServer {
public static SimpleHandler handler;
public static SimpleService.Processor processor;
public static void main(String [] args) {
try {
handler = new SimpleHandler();
processor = new SimpleService.Processor(handler);
InetAddress listenAddress = InetAddress.getByName("localhost");
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(
new InetSocketAddress(listenAddress, 9091));
TTransportFactory transportFactory = new TFramedTransport.Factory(
8 * 1024 * 1024);
THsHaServer.Args serverArgs = new THsHaServer.Args(serverTransport)
.processor(processor)
.transportFactory(transportFactory);
serverArgs.maxReadBufferBytes = (long) (256 * 1024 * 1024);
TServer server = new THsHaServer(serverArgs);
System.out.println("Starting server...");
server.serve();
} catch (Exception x) {
x.printStackTrace();
}
}
}
在这个服务中,只有一个函数接受二进制数据,休眠指定秒数并返回数据长度。请参阅下面的 IDL 和处理程序实现。目的是模拟接受大输入的慢操作,例如数据库批量写入。
simple.thrift
namespace java generated
service SimpleService {
i32 hold(1:i32 seconds, 2:binary data);
}
SimpleHandler.java
public class SimpleHandler implements SimpleService.Iface{
@Override
public int hold(int seconds, ByteBuffer data) throws TException {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data.capacity();
}
}
然后我通过启动 1000 个并发线程来测试此服务器,每个线程发送一个具有 1 秒睡眠时间和 4 MB 二进制数据的请求。
ByteBuffer buffer = ByteBuffer.allocate(4 * 1024 * 1024);
int result = client.hold(1, buffer);
启动测试过程几十秒后,服务器抛出
java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
at AbstractNonblockingServer$FrameBuffer.read(AbstractNonblockingServer.java:352)
at AbstractNonblockingServer$AbstractSelectThread.handleRead(AbstractNonblockingServer.java:184)
at TNonblockingServer$SelectAcceptThread.select(TNonblockingServer.java:182)
at TNonblockingServer$SelectAcceptThread.run(TNonblockingServer.java:133)
我阅读了 Thrift 源代码,知道最大的内存消耗是读取缓冲区的分配。我将serverArgs.maxReadBufferBytes 设置为 256 MB 以防止内存不足。但它仍然会抛出内存不足异常。我确信通过读取源代码和打印一些运行信息来正确限制分配的读取缓冲区。
我不明白为什么它仍然会抛出内存不足异常。
【问题讨论】:
-
1000个线程每个4MB是多少?
Xms和Xmxvm 参数使用什么值? -
硬件上有多少内存可用?
-
@f1sh 每个都是 4MB。我没有设置
Xms和Xmx。他们应该是默认的。我使用jvisualvm查看内存使用情况,最大堆大小约为2G。 -
@Erik 'hw' 是什么意思?我的电脑内存8G,VM最大堆大小2G左右。
-
@gzc 那么这意味着您尝试使用 4+GB 的内存,对吗?为什么 OutOfMemoryError 的最大堆大小为 2G 会让您大吃一惊?