【问题标题】:Preventing high memory usage when using Sockets with NIO使用带有 NIO 的 Sockets 时防止高内存使用
【发布时间】:2013-12-21 08:02:47
【问题描述】:

我正在开发用于文件交换的客户端-服务器架构,这是为了我自己的目的。除了内存使用,一切都很好。在我发送了一些文件后,我意识到当我尝试发送一些视频(大约 900MB)时,我的应用程序内存管理不是那么有效,我的客户端和服务器的内存使用量约为 1.5GB。

我使用了 NetBeans 的 Profiler,它说问题是字节数​​组。

//Client side

FileInputStream f = new FileInputStream(file);
FileChannel ch = f.getChannel();
ByteBuffer bb = ByteBuffer.allocate(8192*32);
int nRead = 0;
while ((nRead = ch.read(bb)) != -1) {
    if (nRead == 0) {
        continue;
    }
    bb.position(0);
    bb.limit(nRead);
    send.writeObject(Arrays.copyOfRange(bb.array(), 0, nRead));
    send.flush();
    bb.clear();   
}
f.close();
ch.close();
bb.clear();
send.writeObject(0xBB);
send.flush();




//Server side

FileOutputStream fos = new FileOutputStream(file);
FileChannel fco = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(8192 * 32);
do {

Object received = download.readObject();
if (received instanceof byte[]) {
    byte[] bytes = (byte[]) received;
    buffer.put(bytes);
    buffer.flip();
    buffer.position(0);
    buffer.limit(bytes.length);
    fco.write(buffer);
    buffer.clear();
} else if (received instanceof Integer) {
    Integer tempx = (Integer) received;
    state = (byte) (tempx & (0xFF));
}
} while (received != (byte) 0xBB);
fco.close();
fos.close();

有没有办法修复它,我的意思是可以清理用过的内存吗?限制字节缓冲区不能正常工作,所以我限制了缓冲区中的字节数组,我没有附加整个代码,因为处理文件是个问题。

来自 PROFILER 的屏幕 - 客户端的内存使用情况 http://i.stack.imgur.com/ouTDk.png

【问题讨论】:

  • 你为什么打电话给send.flush?!您是在测量物理内存还是虚拟内存的使用情况?
  • 抱歉我完全忘记了,发送的是ObjectOutputStream,下载的是ObjectInputStream。
  • 我在 Windows 任务管理器中测量物理内存。
  • 你为什么要创建一个 ByteBuffer 来用字节填充它然后再写出来?不能直接写出byte[]吗?
  • 还值得检查ByteBuffer 上的isDirect() 方法。直接缓冲区经常有奇怪的内存管理策略,可能存在于垃圾收集堆之外。

标签: java file sockets nio


【解决方案1】:
  • 您的缓冲区是 8192 乘以 32。如果您有内存问题,请将它们缩小。出于网络目的,您不需要它们那么大。写 256k 也是一种奇怪的方式。
  • 不要创建无意义的字节数组副本。 ObjectOutputStream.writeUnshared() 将满足您的需要。
  • 我强烈建议摆脱序列化并只复制字节。代码变得更简单,数据副本更少,尤其是在接收端。

【讨论】:

    【解决方案2】:

    这不是直接的解决方案 - 但您应该在所有流上使用 try-with-resources 块。这将防止任何可能使您的情况变得更糟的资源泄漏。

    try (FileOutputStream fos = new FileOutputStream(file)) {
       // Do stuff here, fos is automatically closed when you leave the block
    }
    

    【讨论】:

      猜你喜欢
      • 2019-03-17
      • 1970-01-01
      • 2023-04-10
      • 2014-02-11
      • 2021-10-22
      • 1970-01-01
      • 2018-07-30
      • 2014-05-16
      • 2015-05-04
      相关资源
      最近更新 更多