我的要求是创建输入流的2个副本,一个用于Apache Tika文件MimeType Detect,另一个用于输出流。
private List<InputStream> copyInputStream(final InputStream pInputStream, final int numberOfCopies) throws UploadServiceException{
final int bytesSize = 8192;
List<InputStream> isList = null;
try(PushbackInputStream pushIS = new PushbackInputStream(pInputStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();){
byte[] buffer = new byte[bytesSize];
for (int length = 0; ((length = pushIS.read(buffer)) > 0);) {
baos.write(buffer, 0, length);
}
baos.flush();
isList = new ArrayList();
for(int i = 0; i < numberOfCopies ; i++){
isList.add(new ByteArrayInputStream(baos.toByteArray()));
}
} catch (IOException ex) {
throw new MyException(ErrorCodeEnum.IO_ERROR, ex);
} catch (Exception ex) {
throw new MyException(ErrorCodeEnum.GENERIC_ERROR, ex);
}
return isList;
}
我看到一些性能问题
- 字节数组的大小是文件大小的两倍。我计划使用ByteArrayOutputStream(int size(,但在上传过程中我没有文件大小。
- 我看到垃圾收集不经常发生,如何处理这种情况。
更新
根据反馈
- 删除了回推输入流
添加了最后一个字节[] byteArrayIS = baos.toByteArray((;
private List<InputStream> copyInputStream(final InputStream pInputStream, final int numberOfCopies) throws MyException{ final int bytesSize = 8192; List<InputStream> isList = null; try(ByteArrayOutputStream baos = new ByteArrayOutputStream();){ byte[] buffer = new byte[bytesSize]; for (int length = 0; ((length = pInputStream.read(buffer)) > 0);) { baos.write(buffer, 0, length); } baos.flush(); isList = new ArrayList(); final byte[] byteArrayIS = baos.toByteArray(); for(int i = 0; i < numberOfCopies ; i++){ isList.add(new ByteArrayInputStream(byteArrayIS)); } } catch (IOException ex) { throw new MyException(ErrorCodeEnum.IO_ERROR, ex); } catch (Exception ex) { if(ex instanceof MyException){ throw ex; } throw new MyException(ErrorCodeEnum.GENERIC_ERROR, ex); } return isList; }
字节数组的大小是文件大小的两倍。我计划使用ByteArrayOutputStream(int size(,但在上传过程中我没有文件大小。
如果您必须使用ByteArrayOutputStream
并且对大小没有很好的估计,那么您无能为力。 该ByteArrayOutputStream
使用一种简单(且省时(的策略,即在字节数组填满时将字节数组大小加倍。
ByteArrayOutputStream
的Apache Commons IO版本使用了一种减少复制的替代策略,但它仍然过度分配内存...显著。
我看到垃圾收集不经常发生,如何处理这种情况。
正确的方法是不处理它。 让 GC 在 JVM 确定有必要时运行。 这是迄今为止在Java中进行存储管理的最有效方法。
- 使用
System.gc()
显式运行 GC 可能会对性能造成灾难性影响。
运行 - GC(显式运行或让 JVM 执行此操作(不太可能将内存返回给操作系统。
事实上,GC 不经常运行可能是一件好事。
然后。。。查看您的代码...我可以看到一些东西,这意味着您将使用比您需要的更多的数据副本。
每次调用toByteArray()
时,都会创建ByteArrayOutputStream
捕获的数据的新副本。 对于您正在做的事情,这是不必要的。 相反,您应该在创建单个byte[]
后调用toByteArray()
并将该单个byte[]
包装在多个ByteArrayInputStream
实例中。 您可以确定输入流不会修改byte[]
中的字节。
在您的示例代码中使用PushbackInputStream
似乎没有实现任何效果......这在其他方面是无法实现的。
首先,你为什么使用 PushbackInputStream?这完全无关紧要。您可能希望将输入流包装到 BufferedInputStream 中,如果尚未缓冲输入流。
其次,您是如何测量字节数组大小的?ByteArrayOutputStream 自动管理内部分配。如果 baos.toByteArray(( 给你双倍数据,首先看看你从 InputStream 中实际读取了多少数据(提示:for 循环中所有长度的总和(。
至于垃圾回收,它是自动的和非确定性的,所以如果你对它了解不多,那就别管它了。通常,较少的GC活动意味着有足够的可用内存和/或程序不会产生太多垃圾。这是好事!但是,一旦不再需要它们,您应该确保关闭所有流,否则会出现内存泄漏。特别是,查找 pInputStream 关闭的位置,以及结果列表中所有输入流关闭的位置。