我的代码执行了大量的输入/输出,这通常涉及创建临时数组以保存某些大小的字节或字符 - 我经常使用4096.我开始怀疑 - 没有实际测试 - 来验证它是否会更好地集中这些数组。我的代码会变成这样的
take array from pool
try {
read from one inputStream
write to another outputstream using array
} finally {
return array to pool
}
UPDATE 我写了一个小程序做了两件事,创建了数组并使用了apache commons pool。两者都循环了很多次(100 * 100 * 100)并创建/获取,填充数组,然后释放。我在开始时添加了一些热身jit并忽略了那些结果。每次运行都会在创建和池形式中运行十几次,在两者之间交替。
池和创建表单之间没有什么区别。但是,如果我向一个实例返回池中的apache commons池触发的回调中添加了一个clear数组,那么该池就会比创建的表单慢得多。
答案 0 :(得分:6)
在演示性能问题之前,我不会实现池化。
答案 1 :(得分:4)
对象池增加了应用程序的复杂性。一般来说,你必须处理:
如果你在池实现中出错,你可能会引入潜在的错误。
值得吗?那么,答案取决于具体情况:
如果内存受到严格限制,GC暂停是一个主要问题,和/或分配和初始化对象的成本很高,那么可能是肯定的。
如果“清洁”和对象的成本与分配新成本的摊销成本大致相同,那么这是值得怀疑的。
要理解最后一点,您需要了解一些基本的复制GC人体工程学。特别是如果你:
然后,为Java 中的对象分配和回收内存的摊销GC成本接近归零内存的成本。
因此,如果清理对象的成本大致相当于GC开销(归零)+对象构造函数成本,那么通过池化获得的唯一成果就是减少GC标记/复制发生的次数。但是你可以通过简单地为应用程序提供更大的堆来做同样的事情。
答案 2 :(得分:2)
您可以考虑使用java.nio.Buffer
类。例如,你可以这样:
class ReadWorker {
private ByteBuffer buffer = ByteBuffer.allocate(4096);
public void work() {
fillBufferWithData();
buffer.flip();
doSomethingWithData();
buffer.clear();
}
}
每次调用work
都会清除缓冲区,为下次调用做好准备,但不会一直分配/释放内存。 flip
和clear
是非常快速的操作。
每个工作人员只有一个Buffer
比使用相关的同步娱乐和游戏创建一个游泳池更容易。
编辑:请注意,我假设您生成了一个固定的工作池,因此您不会一直创建新的Buffer
个对象。
如果您没有固定的工作池,那么您可以考虑创建一个Buffer
对象池而不是原始字节数组。这取决于你如何使用它们。
答案 3 :(得分:2)
如果想要使用数组池而不是每次需要数组时都要创建,那么不是一个真正的答案,而是需要考虑的一些要点。
答案 4 :(得分:0)
答案是肯定的。如果您必须执行大量这些输入/输出任务,则池化将提高性能并缩小内存占用量。