繁体   English   中英

多线程访问套接字读取导致jvm OutOfMemory问题

[英]Multiple Threads Accessing the socket read causing jvm OutOfMemory Issue

假设我们有套接字客户端,它正在执行读写操作。 有两个线程在执行发送和接收操作(请求发送者/响应接收者)。 这些线程正在逐个运行Junit测试用例(就像一些压力测试,简单的查询)。 就我而言,我正在运行客户端,它将在DB端与其自身之间建立套接字通信。 在这种逻辑中,请求发送方线程将请求发送到DB端(将请求写入套接字),接收方线程通过读取套接字(从套接字读取响应)来接收响应。 实际问题随机出现。 假设请求发送者线程发送了请求,响应接收者尚未从发送的请求的另一端接收到响应。 在这段时间内,如果有其他测试用例(我的意思是请求线程)启动(在特定的超时时间后,如果没有来自数据库结束的响应)以发送其请求并执行执行,则响应接收器线程具有以下逻辑:

byte[] ofsRes = new byte[size]; 

这部分将收到发生jVm内存不足错误。 我怀疑同时读取响应接收器线程会导致此问题,从而在堆中分配更多大小的字节对象。

从套接字读取数据

int size = dataInputStream.readInt();

您能否帮助任何人解决内存不足错误的问题/可能是线程并发,即使我使用了同步..也没有用。请告诉我您是否需要任何东西。

private static class ResponseReceiver implements Runnable {

        private InputStream _in;
        private List<String> _responses = new ArrayList<String>();
        private int _expectedCount;
        private volatile boolean _finished = false;

        public ResponseReceiver(InputStream in, int expectedCount) {
            _in = in;
            _expectedCount = expectedCount;
        }

        public List<String> getResponses() {
            return _responses;
        }

        public void run() {
            DataInputStream dataInputStream = new DataInputStream(_in);
            try {
                while (true) {
                    _logger.info("_responses.size() >= _expectedCount : -> " + (_responses.size() >= _expectedCount) +
                            " : " + "_responses.size() -> " + _responses.size() + " : " + "_expectedCount -> " + _expectedCount);
                    if (_responses.size() >= _expectedCount) {
                        _finished = true;
                        return;
                    }
                    int size = dataInputStream.readInt();
                    _logger.info("size captured : " + size);
                    if (size > 0) {
                        int readSize = 0;
                        _logger.info( " ofsRes Creating with this size : " + size);
                        **byte[] ofsRes = new byte[size];**
                        while (size > 0) {
                            _logger.info( " Buffer Creating with this size : " + size);
                            byte[] buffer = new byte[size];
                            int bufferSize = _in.read(buffer);
                            _logger.info( " Reading data created Buffer Size : " + bufferSize);
                            System.arraycopy(buffer, 0, ofsRes, readSize,
                                    bufferSize);
                            readSize += bufferSize;
                            _logger.info( " readSize (readSize += bufferSize): " + readSize);
                            size -= bufferSize;
                            _logger.info( " size (size -= bufferSize): " + size);
                        }
                        _responses.add(new String(ofsRes));
                        _logger.info("ofsRes added..");
                    }
                }
            } catch (IOException e) {
                throw new RuntimeException("Error reading data from socket: "
                        + e.getMessage());
            }
        }
    }

执行顺序的跟踪:


2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行信息:_responses.size()> = _expectedCount:-> false:_responses.size()-> 905:_expectedCount- > 2013年5月27日上午1000:com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行信息:捕获的大小:1529 2013年5月27日上午11:45:13 com.xxx.tocf.test。 socket.SocketClient $ ResponseReceiver运行INFO:ofsRes创建具有以下大小:1529 2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:缓冲区创建具有以下大小:1529 May 27 ,2013年11月45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行信息:读取创建的数据缓冲区大小:1529 2013年5月27日11:45:13 com.xxx.tocf.test.socket .SocketClient $ ResponseReceiver运行INFO:readSize(readSize + = bufferSize):1529 2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:Size(大小-= bufferSize): 0 May 27,2013 11:45:13 AM com.xxx.tocf.test.socket.SocketClient $ Re sponseReceiver运行INFO:ofsRes添加。2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:_responses.size()> = _expectedCount:-> false:_responses.size ()-> 906 :_expectedCount-> 1000

假设一个测试用例正在运行,等待响应* ** * ** (906)

2013年5月27日,上午11:45:13 com.xxx.tocf.test.SocketClientTest ofsmlEnqSimpleTest13信息:OFSML 13简单查询测试正在进行中...

另一个案件开始了

2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient发送信息:System.currentTimeMillis():-> 1369635313336:System.currentTimeMillis()-startTime:-> 0:超时-> 5000 :startTime-> 1369635313336:condition:true 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:_responses.size()> = _expectedCount:-> false:_responses。 size()-> 0:_expectedCount-> 1

*假设可能会有不同的阅读*

2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行信息:捕获的大小:195399 2013年5月27日11:45:13 com.xxx.tocf.test.socket。 SocketClient $ ResponseReceiver运行INFO:捕获的大小:1195528239 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:ofsRes使用此大小创建的运行时间:195399 2013年5月27日11:45 :13:com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:ofsRes创建此大小:1195528239 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:具有此大小的缓冲区创建:195399 线程“ Thread-22”中的异常java.lang.OutOfMemoryError: com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver.run(SocketClient.java:147)处的Java堆空间 java.lang.Thread.run(Thread.java:662)2013年5月27日,上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:读取创建的数据缓冲区大小:759 5月27日, 2013 11:45:13 AM com.xxx.tocf.test.so cket.SocketClient $ ResponseReceiver运行INFO:大小(大小-= bufferSize):759 2013年5月27日上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:大小(大小-= bufferSize) :194640 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:缓冲区创建时使用以下大小:194640 2013年5月27日11:45:13 AM com.xxx.tocf .test.socket.SocketClient $ ResponseReceiver运行INFO:读取创建的数据缓冲区大小:1533 2013年5月27日,上午11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:readSize(readSize + = bufferSize ):2292 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:size(size-= bufferSize):193107 2013年5月27日11:45:13 com。 xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:缓冲区使用以下大小创建:193107 2013年5月27日11:45:13 com.xxx.tocf.test.socket.SocketClient $ ResponseReceiver运行INFO:读取创建的数据缓冲区大小:767

假设发送方线程是否在等待来自另一端的特定响应。

为什么? 您已经有一个接收者线程。

在这段时间内,如果其他任何测试用例(我是指线程)开始推送其请求并执行执行手段,则响应接收器线程的逻辑为

byte[] ofsRes = new byte[size];

size的价值从何而来? 发送方线程和接收方线程都试图读取响应的确切含义是什么? 我不知道您期望发生什么,但是将要发生的事情是完全不确定的。 这没有任何意义。 您需要确定谁应该读取响应,然后让他们读取。 可能您需要在发送方和接收方线程之间引入一些同步,以便发送方直到接收方收到上一个请求的结果后才发送下一个请求。 更好的是,摆脱接收线程,让发送线程接收自己的响应。

这部分将收到发生jVm内存不足错误。

当然会。 它从某处获取一个基本上是size随机的值,并试图分配一定数量的内存,因此它也是随机的。

我怀疑同时读取响应接收器线程会导致此问题,从而在堆中分配更多大小的字节对象。

再次正确。 解决方案是不这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM