输入流输出流是以内存为标准

由于某种原因,我需要非常大的,甚至可能是无限的InputStream ,它会反复地反复返回相同的byte[] 。 这样,我可以通过重复小样本来产生疯狂的大数据流。 可以在Guava中找到类似的功能: Iterable<T> Iterables.cycle(Iterable<T>)Iterator<T> Iterators.cycle(Iterator<T>) 。 例如,如果您需要01的无限来源,只需说出Iterables.cycle(0, 1)并无限获取Iterables.cycle(0, 1) 0, 1, 0, 1, 0, 1... 不幸的是,我还没有为InputStream找到这样的工具,所以我跳入自己编写的工具。 本文记录了我在此过程中犯的许多错误,主要是由于过于复杂和过度设计的简单解决方案。

我们实际上并不需要无限的InputStream ,能够创建非常大的InputStream (例如32 GiB)就足够了。 因此,我们采用以下方法:

public static InputStream repeat(byte[] sample, int times)

它基本上采用字节sample数组,并返回一个InputStream返回这些字节。 但是,当sample用完时,它将翻转,再次返回相同的字节-重复此过程指定的次数,直到InputStream信号结束。 我尚未真正尝试过但似乎最显而易见的一种解决方案:

public static InputStream repeat(byte[] sample, int times) {final byte[] allBytes = new byte[sample.length * times];for (int i = 0; i < times; i++) {System.arraycopy(sample, 0, allBytes, i * sample.length, sample.length);}return new ByteArrayInputStream(allBytes);
}

我看到你在那笑! 如果sample是100个字节,并且我们需要32 GiB的输入重复这100个字节,则生成的InputStream不应真正分配32 GiB的内存,我们在这里必须更加聪明。 实际上,上面的repeat()有另一个细微的错误。 Java中的数组限制为2 31 -1个条目( int ),比其高32 GiB。 该程序编译的原因是此处无声的整数溢出: sample.length * times 。 此乘法不适用于int

好的,让我们尝试至少在理论上可行的方法。 我的第一个想法是:如果我创建多个ByteArrayInputStream共享相同的byte[] sample (它们不进行急切的复制),然后以某种方式将它们连接在一起怎么办? 因此,我需要一些InputStream适配器,该适配器可以采用任意数量的基础InputStream并将它们链接在一起-当第一个流耗尽时,切换到下一个。 当您在Apache Commons或Guava中寻找某些东西,并且显然永远在JDK中时,这一尴尬时刻… java.io.SequenceInputStream几乎是理想的选择。 但是,它只能精确地链接两个基础InputStream 。 当然,由于SequenceInputStream本身就是InputStream ,我们可以递归地将其用作外部SequenceInputStream的参数。 重复此过程,我们可以将任意数量的ByteArrayInputStream在一起:

public static InputStream repeat(byte[] sample, int times) {if (times <= 1) {return new ByteArrayInputStream(sample);} else {return new SequenceInputStream(new ByteArrayInputStream(sample),repeat(sample, times - 1));}
}

如果times为1,则将sample包装在ByteArrayInputStream 。 否则,递归使用SequenceInputStream 。 我认为您可以立即发现此代码的问题:太深的递归。 嵌套级别与times参数相同,将达到数百万甚至数十亿。 肯定有更好的办法。 幸运的是,较小的改进将递归深度从O(n)更改为O(logn):

public static InputStream repeat(byte[] sample, int times) {if (times <= 1) {return new ByteArrayInputStream(sample);} else {return new SequenceInputStream(repeat(sample, times / 2),repeat(sample, times - times / 2));}
}

老实说,这是我尝试的第一个实现。 这是分而治之原理的简单应用 ,在这里我们将结果平均分成两个较小的子问题。 看起来很聪明,但是有一个问题:容易证明我们创建了t( t =timesByteArrayInputStreams和O(t) SequenceInputStream 。 共享sample字节数组时,数百万个各种InputStream实例浪费了内存。 这导致我们可以选择实现,无论times多少, InputStream创建一个InputStream

import com.google.common.collect.Iterators;
import org.apache.commons.lang3.ArrayUtils;public static InputStream repeat(byte[] sample, int times) {final Byte[] objArray = ArrayUtils.toObject(sample);final Iterator<Byte> infinite = Iterators.cycle(objArray);final Iterator<Byte> limited = Iterators.limit(infinite, sample.length * times);return new InputStream() {@Overridepublic int read() throws IOException {return limited.hasNext() ?limited.next() & 0xFF :-1;}};
}

毕竟,我们将使用Iterators.cycle() 。 但是在我们必须将byte[]转换为Byte[]因为迭代器只能与objets一起使用,而不能与原语一起使用。 没有惯用的方法ArrayUtils.toObject(byte[])语数组转换为盒装类型数组,因此我使用来自Apache Commons Lang的ArrayUtils.toObject(byte[]) 。 有了对象数组,我们可以创建一个infinite迭代器,循环遍历sample值。 由于我们不需要无限的流,因此再次使用了来自Guava的Iterators.limit(Iterator<T>, int)来切断无限迭代Iterators.limit(Iterator<T>, int) 。 现在,我们只需要从Iterator<Byte>InputStream进行桥接–毕竟它们在语义上代表同一件事。

该解决方案遭受两个问题。 首先,由于拆箱,它会产生大量垃圾。 垃圾回收并不太关心死的,短命的物品,但看起来仍然很浪费。 我们之前已经遇到的第二个问题: sample.length * times乘以倍数可能会导致整数溢出。 由于Iterators.limit()占用intlong ,因此没有固定的理由,因此无法修复。 顺便说一句,我们通过按位 0xFF避免了第三个问题-否则,值为-1 byte将表示流的结束,事实并非如此。 x & 0xFF已正确转换为无符号255int )。

因此,即使上面的实现是简短而甜美,声明式而不是命令式的,但它仍然太慢且受限制。 如果您有C背景,我可以想象您看到我挣扎时会感到多么不舒服。 在我最后想到的是最简单,痛苦的简单和低级的实现之后:

public static InputStream repeat(byte[] sample, int times) {return new InputStream() {private long pos = 0;private final long total = (long)sample.length * times;public int read() throws IOException {return pos < total ?sample[(int)(pos++ % sample.length)] :-1;}};
}

无GC的纯JDK,快速,简单易懂。 让这成为您的一个教训:从您想到的最简单的解决方案开始,不要过度设计并且不要太聪明。 我以前的解决方案(声明性,功能性,不变性等)–也许它们看起来很聪明,但是它们既不快速也不容易理解。

我们刚刚开发的实用程序不仅是一个玩具项目,还将在后续文章中使用 。

翻译自: https://www.javacodegeeks.com/2014/07/building-extremely-large-in-memory-inputstream-for-testing-purposes.html

输入流输出流是以内存为标准

输入流输出流是以内存为标准_构建用于测试的超大内存输入流相关推荐

  1. 构建用于测试的超大型内存InputStream

    由于某种原因,我需要非常大的,甚至可能是无限的InputStream ,它会反复地反复返回相同的byte[] . 这样,我可以通过重复小样本来产生大量的数据流. 在Guava中可以找到类似的功能: I ...

  2. 软件测试 测试停止标准_停止正常测试

    软件测试 测试停止标准 I see a lot of data scientists using tests such as the Shapiro-Wilk test and the Kolmogo ...

  3. redis 内存不足 排查_一文深入了解 Redis 内存模型,Redis 的快是有原因的!

    前言 一.Redis内存统计 二.Redis内存划分 1.数据 2.进程本身运行需要的内存 3.缓冲内存 4.内存碎片 三.Redis数据存储的细节 1.概述 2.jemalloc 3.redisOb ...

  4. keil内存溢出表现_详细讲解C语言五大内存分区与可执行程序的三段(Text段、Date段、Bss段)【建议收藏】...

    一.c语言五大内存分区 栈区(stack):存放函数形参和局部变量(auto类型),由编译器自动分配和释放. 堆区(heap):该区由程序员申请后使用,需要手动释放否则会造成内存泄漏.如果程序员没有手 ...

  5. linux运行java程序内存过大_排查java应用linux环境内存占用过高的问题

    一.问题场景 在一个短信平台的项目中,设置了一个下发节点的Xmx为16G,但是出现了内存撑满,导致CPU过高的情况.当时的具体情况是,该应用内存占用16G,该应用CPU占用1400%(16核),服务器 ...

  6. 苹果内存不够怎么办_苹果手机到底买多大内存合适?

    实体店地址详细:实体店地址 回收/置换手机点击:三哥正式开始回收手机啦! 手机回收小程序:手机淘回收 近来许多粉丝向我提问:苹果手机买多大内存合适?64G内存够不够用?针对这类问题,三哥今天统一作一个 ...

  7. sdp ddp内存怎么分_映众iCHILL DDR4 RGB内存开箱测试,时序和频率同样重要

    开箱和灯光展示 内存自从加LED灯以后,越来越多的内存品牌浮现,加上目前RGB同步效果的盛行,就在去年底,以公版PCB和散热著名的映众Inno3D也推出了自己的内存-iCHILL系列,这个系列是与iC ...

  8. python编程8g的内存够么_计算机学科大学生购买8G内存笔记本是否够用?

    目前低价位轻薄本里面能升级内存的也只有两种型号:联想小新Air和惠普战66 首先,轻薄本的CPU无论是i5还是i7,两者的性能差别都不大,因为它们的核心和线程是一样,唯一的差别是i7的睿频稍微高一点, ...

  9. python读取视频占用内存太大_视频流用多进程读写,内存溢出怎么办?

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 import gc import os from multiprocessing import Manager, Process import cv2 v ...

最新文章

  1. linux 自动ping脚本,linux上ping脚本及zabbix3.xx上自动发现
  2. 认识httphandler
  3. express ajax分页实例,element+express+mongoose实现分页查询
  4. 安装icephp 记
  5. 华为驳斥鸿蒙六月上线,终于来了!华为鸿蒙6月初将正式上线手机
  6. 【剑指offer】_01 (二维数组中的查找)
  7. php sem acquire,PHP | 关于php中sem_get failed for key no space left on device问题的解决方案...
  8. multisim模拟电子钟课设带视频报告下载
  9. UI数据缓冲层的设计(-)
  10. Alpha冲刺 - (6/10)
  11. 【总结】Apache Sentry 服务简介
  12. PCB Layout的设计要点
  13. 设为首页 加入收藏代码
  14. 企业软件,WEB和对于他们无限美好的遐想(第五日)--2014-3-14--IT日 + Struts 原理分析 (四)
  15. html5移动端webscoket实现在线聊天
  16. 【最优化基础】惩罚和障碍函数
  17. csgo 简单发光透视
  18. 日赚1.7亿!华为发布2020年度财报!附华为十大5G应用场景
  19. 基于java的网上鲜花销售系统,基于JAVA的鲜花销售管理系统MVC开发,免费分享
  20. 品鑒「天籁般的印第安音乐,每次聆听都是一场心灵的洗礼」2019年 06月27星期四

热门文章

  1. P3076,jzoj3187-的士【贪心】
  2. jzoj3084-超级变变变【数学】
  3. 【dfs】拔河比赛(ybtoj dfs-1-1)
  4. 【链表】【树形DP】最大利润(jzoj 1487)
  5. Summer Training day4 欧拉降幂
  6. 动态规划训练8 [E - Multiplication Puzzle POJ1651]
  7. Spring @Import注解配置类方法内部调用没有注入属性值的坑
  8. 汇编语言(十八)之求两个数的最大公约数
  9. 浅谈MySQL的B树索引与索引优化
  10. Java最小堆解决TopK问题