gpt4 book ai didi

java - 如何获取使用 RMI 发送的对象的字节大小?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:55:19 25 4
gpt4 key购买 nike

我正在使用 MongoDB 和 ConcurrentHashMap java 类实现缓存服务器。当内存中有可用空间放置对象时,它会放在。否则,该对象将保存在 mongodb 数据库中。允许用户为内存缓存指定内存大小限制(这显然不应超过堆大小限制!)。客户端可以使用通过 RMI 连接的缓存服务。我需要知道每个对象的大小,以验证是否可以将新传入的对象放入内存。我在互联网上搜索并得到了这个解决方案来获得尺寸:

  public long getObjectSize(Object o){
try {

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(o);
oos.close();

return bos.size();
} catch (Exception e) {
return Long.MAX_VALUE;
}
}

这个解决方案非常有效。但是,就内存使用而言并不能解决我的问题。 :( 如果许多客户端同时验证对象大小,这将导致堆栈溢出,对吗?好吧......有些人会说:为什么你不获取特定对象大小并将其存储在内存中,而当另一个对象是需要在内存中检查对象大小吗?这是不可能的,因为对象的大小是可变的。:(

有人可以帮助我吗?我在考虑从 RMI 通信中获取套接字,但我不知道该怎么做...

最佳答案

您可以使用自定义 FilterOutputStream 解决限制序列化对象大小的问题:

  1. 计算 write 方法调用写入的字节数,并且
  2. 当计数超过您的限制时抛出一个自定义的 IOException 子类。

然后将此过滤器放在 ByteArrayOutputStreamObjectOutputStream 之间。

这是代码的样子(未经测试!):

    public LimitExceededException extends IOException { ... }

public class LimitingOutputStream extends FilterOutputStream {
private int limit;
private int count;

public LimitingOutputStream(OutputStream out, int limit) {
super(out);
this.limit = limit;
}

@Override
public void write(byte b) throws IOException {
if (count++ > limit) {
throw LimitExceededException(...);
}
super.write(b);
}

@Override
// (This override is not strictly necessary, but it makes it faster)
public void write(byte[] bytes, int from, int size) throws IOException {
if (count += size > limit) {
throw LimitExceededException(...);
}
super.write(bytes, from, size);
}
}

/**
* Return the serialization of `o` in a byte array, provided that it is
* less than `limit` bytes. If it is too big, return `null`.
*/
public byte[] serializeWithLimit(Object o, int limit) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LimitingOutputStream los = new LimitingOutputStream(bos, limit);
ObjectOutputStream oos = new ObjectOutputStream(los);
oos.writeObject(o);
oos.close();
return bos.toByteArray();
} catch (LimitExceededException e) {
return null;
}
}

是的,这会在超出限制时使用异常“退出”,但这是 IMO 对异常的良好使用。我挑战任何不同意这一点的人提出更好的解决方案。放在另一个答案里。


顺便说一句,这是非常糟糕的代码:

} catch (Exception e) {
return Long.MAX_VALUE;
}

除了您可能会抛出的 IOException 之外,您还会捕获各种未经检查的异常,其中大部分是由您需要知道的错误引起的关于:

  1. 捕捉 Exception 是不好的做法,除非您尝试进行最后的诊断。

  2. 无论何时捕获意外异常,请务必记录它们,以便记录堆栈跟踪(取决于记录器配置)。或者,如果您的应用程序不使用日志记录框架,则让它调用 e.printStackTrace()

(如果您不会在生产代码中这样做,也不要在 StackOverflow 问题中这样做...因为一些复制粘贴编码器可能只是复制它。)

关于java - 如何获取使用 RMI 发送的对象的字节大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13100912/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com