【问题标题】:Simple Java Thrift server raises Out Of Memory Exception简单的 Java Thrift 服务器引发内存不足异常
【发布时间】: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是多少? XmsXmx vm 参数使用什么值?
  • 硬件上有多少内存可用?
  • @f1sh 每个都是 4MB。我没有设置XmsXmx。他们应该是默认的。我使用jvisualvm查看内存使用情况,最大堆大小约为2G。
  • @Erik 'hw' 是什么意思?我的电脑内存8G,VM最大堆大小2G左右。
  • @gzc 那么这意味着您尝试使用 4+GB 的内存,对吗?为什么 OutOfMemoryError 的最大堆大小为 2G 会让您大吃一惊?

标签: java thrift


【解决方案1】:

您需要在客户端使用TFramedTransport。此传输由您选择的服务器隐式应用,或者换句话说:服务器希望客户端使用它。

我已经在我的测试程序中使用了 TFramedTransport。 应该和这个无关

是的,确实如此。你用在服务器端,我只讲客户端。

Several server types imply the usage of TFramedTransport,它已经内置了。在服务器端添加另一个将需要您在客户端有 两个 TFramedTransport 实例,这显然是没有意义的。

所以你

  • 需要客户端
  • 服务器端不需要THsHaServer

我不明白为什么它仍然会抛出内存不足异常。

但你知道得更好......

【讨论】:

  • 我已经在我的测试程序中使用了TFramedTransport。应该与此无关。
  • 你并没有真正理解我的回答。我会让它更详细。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 2010-09-13
  • 2015-02-16
  • 2011-01-09
  • 2012-05-06
相关资源
最近更新 更多