简体   繁体   English

删除分配给字节数组的 memory

[英]delete memory allocated to a byte array

I am receiving records in while loop at a socket server.我在套接字服务器的 while 循环中接收记录。 where each records has a msg type followed by message length and actual message content.其中每条记录都有一个 msg 类型,后跟消息长度和实际消息内容。

The problem is that since I get around a million records and each record has a record size of 277 bytes.问题是因为我得到了大约一百万条记录,并且每条记录的记录大小为 277 字节。 So, after around 40000 records, I get OutOfMemory error.因此,在大约 40000 条记录之后,我得到 OutOfMemory 错误。 The code flow looks something like this:代码流看起来像这样:

while (true) {              
            msgType = dIn.readByte();

            int msgIntType = msgType & 0xff;

                  // get message length

                  int msgIntLen = dIn.readInt();
                  if (msgIntLen != 0) {

     msgContent = new byte[msgIntLen];
                   switch(msgIntType) {
            case 4:
            //case MSG_DATA:
                // MSG_DATA
                recordCount++;
                processData(msgContent);
                if (recordCount == 2000) {
                sendACK(dOut, msgIntType);
                logger.info("sent ACK for MSG_DATA");
                recordCount = 0;
                }               
                break;

}

I resolved the OutOfMemory issue by explicitly calling System.gc() after sending ACK after every 2000 records processed and now it works perfectly fine and able to handle 1 million records without any error in less than 10 minutes.我通过在每处理 2000 条记录后发送 ACK 后显式调用 System.gc() 解决了 OutOfMemory 问题,现在它工作得非常好,能够在不到 10 分钟的时间内处理 100 万条记录而没有任何错误。 The modified code for case statement for calling System.gc() looks like:用于调用 System.gc() 的 case 语句的修改代码如下所示:

            case 4:
            //case MSG_DATA:
                // MSG_DATA
                recordCount++;
                processData(msgContent);
                if (recordCount == 2000) {
                sendACK(dOut, msgIntType);
                logger.info("sent ACK for MSG_DATA");
                recordCount = 0;
                             System.gc();
                }               
                break;

But I read here on some other posts that calling System.gc() is not a good design approach?但是我在这里读到其他一些帖子,调用 System.gc() 不是一个好的设计方法? Is it so?是这样吗? If yes, could you guys suggest me some other way to get rid of this OutOfMemory error?如果是的话,你们能建议我用其他方法来摆脱这个 OutOfMemory 错误吗?

Thanks in advance -JJ提前致谢-JJ

EDIT: logic for processData():编辑:processData() 的逻辑:

public void processData(byte[] msgContent) throws Exception {

    InputStreamReader inp = new InputStreamReader(

            new ByteArrayInputStream(msgContent));

    BufferedReader br = null;
    try {

        br = new BufferedReader(inp);
                             String line;
        while ((line = br.readLine()) != null) {

                             process each line
                             .
                             }
                  } catch (Exception e) {
        logger.error("exception in " + Utils.getExecutingMethodName(e) 
                + " :" + e.getMessage());
    } finally {
        try {
            if (br != null)
                br.close();
        } catch (IOException e) {
            logger.error("Error: " + e);
        }
    }
}

Are you failing to close some resource and relying upon the finaliser thread to pick them up?您是否未能关闭某些资源并依赖终结器线程来获取它们? Or have you just added a finaliser (probably unnecessary) that is preventing a significant amount of memory to be freed promptly.或者您是否刚刚添加了一个终结器(可能是不必要的),它阻止了大量的 memory 被及时释放。

If that is literally the only change you made, it is difficult to see how that would fix the problem.如果这实际上是您所做的唯一更改,那么很难看出这将如何解决问题。 Whenever the Java Virtual Machine is running low on memory, it runs the garbage collector automatically before throwing an out of memory exception.每当 Java 虚拟机在 memory 上运行不足时,它会在抛出 memory 异常之前自动运行垃圾收集器。 There should be no need to do this yourself nor any value in doing so.自己没有必要这样做,这样做也没有任何价值。

The only real solution to the problem you describe is to make sure that you clear out any references to objects that are no longer needed.您描述的问题的唯一真正解决方案是确保清除对不再需要的对象的任何引用。 Like if you say:就像你说:

byte[] ba=new byte[bignumber];
process(ba);

and then you go on and do other things, ba is still sitting there hogging up memory.然后你 go 继续做其他事情,ba 仍然坐在那里占用 memory。 You want to either exit the function where it was defined, or set ba=null to lose the reference.您想退出定义它的 function,或者设置 ba=null 以丢失引用。 Then the gc can recycle the memory.然后gc可以回收memory。

Is there a maximum size to the data you receive (or can you enforce one)?您收到的数据是否有最大大小(或者您可以强制执行)? In which case you can declare your byte array outisde the while and reuse it at each iteration without allocating more memory:在这种情况下,您可以同时声明您的字节数组并在每次迭代中重用它,而无需分配更多的 memory:

...
private static final int BUFFER_SIZE = 102400; //start with a buffer big enough to lower the chances of resizing it -- e.g. 100K
...
msgContent = new byte[BUFFER_SIZE];
while (true) {              
            msgType = dIn.readByte();

            int msgIntType = msgType & 0xff;

                  // get message length

                  int msgIntLen = dIn.readInt();
                  if (msgIntLen != 0) {
                   if( msgIntLen > msgContent.length ) //only resize when needed otherwise reuse
                     msgContent = new byte[msgIntLen];

                   switch(msgIntType) {
            case 4:
            //case MSG_DATA:
                // MSG_DATA
                recordCount++;
                processData(msgContent, msgIntLen); //need to change your function to also pass in the size of the message read!
                if (recordCount == 2000) {
                sendACK(dOut, msgIntType);
                logger.info("sent ACK for MSG_DATA");
                recordCount = 0;
                }               
                break;

}

What is the the type of your dIN variable?您的dIN变量的类型是什么? Maybe I am misunderstanding, but do you really need to read your input into a byte array, then consider the byte array as a stream, and then read the stream line by line?也许我理解错了,但是你真的需要将你的输入读入一个字节数组,然后将字节数组视为stream,然后逐行读取stream吗? If you already know the structure of your content, why create all the intermediate steps.如果您已经知道内容的结构,为什么还要创建所有中间步骤。 You could just as well process(dIn) somehow.你也可以以某种方式process(dIn)

Also, just to confirm, is this running in a multi-threaded environment??另外,只是为了确认一下,这是否在多线程环境中运行?

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

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