我的java程序在测试性能时遇到内存泄漏的问题。
大概情况是这样的,我用udp发送数据,一条数据长度为8192byte,在外部的循环中发送10000次。
jvm的参数是-Xms256M -Xmx256M。
在测试过程中经常出现内存不足的问题,一般发送4800条左右就报内存不足的exception了。
经过调查大概有两处地方导致。
一处是在发送数据前我对数据处理调用过System.arraycopy的方法,这里我改为for循环来拷贝数组就通过了。
另一处是socket.send(packet);这处只要我注释掉这条语句10000条就可以通过,20000或30000都没有问题,但是只要一打开这条语句就会报内存不足。这处我绕不过去了,很是着急。下面是一点代码片段,这个片段就是循环中发送数据的代码,是在一个线程的run方法中被调用的
                String strMessage = sendIterator.next();
                byte[] buf = message.getMessageContent(strMessage);
                DatagramPacket packet = new DatagramPacket(
                    buf,
                    buf.length,
                    address,
                    message.getNetInfo().GetPort());
                socket.send(packet);
另外,在message.getMessageContent中调用了System.arraycopy。
public synchronized byte[] getMessageContent(String data) {
        byte[] temp;        if(netInfo.GetAddLen()) {
            data = (TrxSimUtil.getHexFormat(data.length() / 2) + data);
        }        if(netInfo.GetDataMode() == TrxSimConstant.BINARY) {
            temp = transferAsciiToBinary(data);
        } /* end of if */
        else {
            temp = data.getBytes();
        } /* end of else */        int length = temp.length;        if(netInfo.GetAddBit()) {
            length += 2;
        } /* end of if */        int start = 0;
        byte[] content = new byte[length];
        if(netInfo.GetAddBit()) {
            start = 1;
            content[0] = 2;
            content[length - 1] = 3;
        } /* end of if */        //System.arraycopy(temp, 0, content, start, temp.length);
        for( int i=0; i<temp.length ; i++ ){
         content[start+i] = temp[i];
        }
        return content;
    } /* end of function */

解决方案 »

  1.   

    再说明一点,如果我在最后加一条packet.setData(null),
    则10000次可以通过,但是美中不足的是会抛几条exception(在10000次中),
    虽然感觉这exception对数据发送似乎没有什么影响,因为单独发一条是可以确认发出去的。代码片段如下:
                    String strMessage = sendIterator.next();
                    byte[] buf = message.getMessageContent(strMessage);
                    DatagramPacket packet = new DatagramPacket(
                        buf,
                        buf.length,
                        address,
                        message.getNetInfo().GetPort());
                    socket.send(packet);
                    packet.setData(null);
      

  2.   

    socket.send(packet);之后立刻把buf变成nill试试看
      

  3.   

    像这种问题一般都是有些变量在使用过以后没有清除掉所致,所以一直在内存中。你试试把使用后应该清除的变量在使用后置为null,一般应该没有什么问题。
    记得在使用数据库连接池的时候如果循环后没有关掉,则小容量数据时没有问题,一到大批量数据的时候就报错,检查的时候真是出汗:怎么会犯这种错误...
      

  4.   

    String strMessage = sendIterator.next();
                    byte[] buf = message.getMessageContent(strMessage);
                    DatagramPacket packet = new DatagramPacket(
                        buf,
                        buf.length,
                        address,
                        message.getNetInfo().GetPort());
                    socket.send(packet);
                    packet = null ;
      

  5.   

    你的 for 循环到底多块,数据来得及发送完么? 会不会都阻塞了?循环中数据保存时间长的话还真应该 xxx = null.
      

  6.   

    既高兴又遗憾的告诉大家,这个内存泄漏的问题已经被我的同事解决了,但是仍然没有找到问题所在。目前怀疑与StringBuilder有关。
    解决的要点是:
    待发送的数据,是String型,会先调一个函数处理一下,其中使用了StringBuilder,
    然后会对这个StringBuilder调toString取得内容继续使用。
    现在改为,不用StringBuilder而用String类型,就通过了。旧代码片断:
    (1)
            StringBuilder validData = new StringBuilder();
            checkDataLengthCorrect(netInfo, data, validData);
            data = validData.toString();
    (2)
        public static boolean checkDataLengthCorrect(
            NetInfo netInfo,
            String data,
            StringBuilder validData) {
            int length = data.length() / 2;        if(length > TrxSimConstant.COMM_MAX_BUFFER) {
                validData.append(data.substring(
                    0,
                    TrxSimConstant.COMM_MAX_BUFFER * 2));
                return true;
            }
            else {
                validData.append(data);
                return false;
            }
        }新代码片断:
    (1)
            StringBuilder validData = new StringBuilder();
            data = checkDataLengthCorrect(netInfo, data, validData);
    (2)
    public static String checkDataLengthCorrect(
                NetInfo netInfo,
                String data,
                StringBuilder validData) {
            int length = data.length() / 2;        if(length > TrxSimConstant.COMM_MAX_BUFFER) {
                validData.append(data.substring(
                    0,
                    TrxSimConstant.COMM_MAX_BUFFER * 2));
                data = data.substring(
                        0,
                        TrxSimConstant.COMM_MAX_BUFFER * 2);
                //return true;
            }
            else {
                validData.append(data);
                //return false;
            }
            return data;
        }说明:
    代码(1)是在一个用于往待send的数据集合添加待send数据的函数中被调用的。
    然后另外有一个线程从这个数据集合中取数据一条条实际send出去。
      

  7.   

    我推荐你看看o'rally的java多线程和java网络编程III,特别是后者,可使你的代码更有效。