Поток памяти в Java

Я ищу реализацию потока памяти в Java. Реализация должна быть примерно смоделирована после потока памяти .NET реализация.

В основном я хотел бы иметь класс MemoryStream, который имеет фабричные методы:

 class MemoryStream {
     MemoryInput createInput();
     MemoryOutput createOutput();
 }

 class MemoryInput extends InputStream {
    long position();
    void seek(long pos);
 }

 class MemoryOutput extends OutputStream {
    long position();
    void seek(long pos);
 }

Итак, когда у меня есть экземпляр из класса MemoryStream, я должен иметь возможность одновременно одновременно создавать потоки ввода и вывода, что также должно позволять позиционирование в любом направлении. Поток памяти не обязательно должен быть круговым, он должен хорошо работать для небольших размеров и автоматически увеличиваться. Поток памяти должен быть ограничен только одним процессом.

Доступен код из коробки?


person Mostowski Collapse    schedule 08.12.2011    source источник


Ответы (4)


ByteArrayInputStream и ByteArrayOutputStream — это то, что вам нужно.

Это реализации интерфейсов InputStream и OutputStream, которые считывают и записывают массив байтов в памяти. Для ByteArrayOutputStream массив будет расти автоматически по мере записи данных в поток.

person Jesper    schedule 08.12.2011
comment
ByteArrayInputStream поддерживает mark() и reset() для обозначения позиции в потоке, чтобы вы могли вернуться туда позже. ByteArrayOutputStream этого нет. Предложение Питера Лоури с использованием NIO ByteBuffer, вероятно, более полезно. - person Jesper; 09.12.2011
comment
Позволяет ли это позиционировать в любом направлении? - person Mostowski Collapse; 09.12.2011
comment
Ну эти ByteBuffers, я пока не уверен. Проблема заключается в общем понимании нефункциональных требований: частота, объем данных и тип доступа. В зависимости от того, что они могут быть хорошей или плохой идеей. - person Mostowski Collapse; 09.12.2011
comment
Итак, окончательное решение (без случайного позиционирования) ByteArrayOutputStream inMemoryStream = new ByteArrayOutputStream(); /* write into stream */; ByteArrayInputStream inputStream = new ByteArrayInputStream(inMemoryStream.toByteArray()); /* read from the inputStream */ - person Lu55; 18.11.2017

Вы можете использовать PipedInputStream и PipedOutputStream

нравится:

PipedOutputStream outstr = new PipedOutputStream();
PipedInputStream instr = new PipedInputStream(outstr);

это не позволит вам напрямую искать, но позволяет пропустить столько байтов, сколько вы хотите, из входного потока.

Имейте в виду, что всякий раз, когда вы записываете в outstr, он блокируется до тех пор, пока все не будет прочитано из instr (то есть: если я правильно помню, потоки не буферизуются, но вы можете украсить их с помощью BufferedInputStream, тогда вам не нужно беспокоиться .

person Angelo Fuchs    schedule 08.12.2011

Нужно ли поддерживать потоки ввода и вывода? Если нет, я бы просто использовал ByteBuffer, который позволяет вам читать/записывать примитивные типы в случайных местах. (до 2 ГБ)

Вы можете совместно использовать ByteBuffer между читателем и писателем.

e.g.

// 1 GB of virtual memory outside the heap.
ByteBuffer writer = ByteBuffer.allocateDirect(1024*1024*1024); 
ByteBuffer reader = writer.slice();

Вы можете совместно использовать память между потоками (например, Exchanger) и процессами (используя файлы с отображением памяти)

person Peter Lawrey    schedule 08.12.2011
comment
Как использовать для маленьких размеров? Будет ли он автоматически расти? - person Mostowski Collapse; 09.12.2011
comment
Он не растет автоматически как таковой. Однако, если вы делаете прямые буферы намного больше, чем вам нужно, но не используете их, ОС не выделяет память вашему процессу. - person Peter Lawrey; 09.12.2011
comment
Ага, ок, я не знал. Это гарантировано для ОС и JVM? - person Mostowski Collapse; 09.12.2011
comment
Да, ввод/вывод обязателен. Так что я могу подключиться к существующему приложению. - person Mostowski Collapse; 09.12.2011
comment
Да, приложение фактически делает произвольный доступ через RandomAccessFile, а не через потоки ввода/вывода. А вот из RandomAccessFile порождает входные/выходные потоки. Но чтобы не усложнять ситуацию, я опубликовал приведенную выше спецификацию интерфейса. - person Mostowski Collapse; 09.12.2011
comment
Вам нужен RandomAccessFile в памяти? Можно ли использовать файловую систему tmpfs или аналогичную? Вам даже не нужно будет менять свой код. - person Peter Lawrey; 09.12.2011
comment
На самом деле идея состоит в том, чтобы заменить временные файлы через потоки памяти. Так что имена временных файлов не видны и не нуждаются в управлении. - person Mostowski Collapse; 09.12.2011
comment
Вы можете сделать их deleteOnExit() и поместить в скрытый каталог. - person Peter Lawrey; 09.12.2011
comment
Согласованный. Тогда есть производительность, нужны потоки памяти для высокочастотных манипуляций небольшого размера. 10-50 байт, что-то вроде StringBuilder, но вместо вставки() используется запись(). - person Mostowski Collapse; 09.12.2011
comment
В этом случае использование RandomAccessFile может занять 1–3 микросекунды, тогда как доступ к памяти будет относительно быстрым (0,05–0,5 мкс). Я бы обернул ByteBuffer(s) с помощью Input/OutputStreams, если вам нужно их использовать. Это довольно просто. К сожалению, размер каждого ByteBuffer ограничен 2 ГБ (у вас должна быть 64-битная JVM, чтобы использовать столько BTW) - person Peter Lawrey; 09.12.2011
comment
Позже он также должен работать на устройствах Android. Пока не проверял, есть ли у них ByteBuffer. Полагаю, что так. - person Mostowski Collapse; 09.12.2011
comment
Они делают, но это приносит столько же пользы. В Java ByteBuffers обеспечивают самый низкий уровень доступа к памяти без использования Unsafe или JNI. - person Peter Lawrey; 09.12.2011
comment
Меньше, чем byte[] ? Может и нет GC, или менее хороший GC, а то они плохие для моей высокой частоты 10-50 байт. - person Mostowski Collapse; 09.12.2011
comment
Ниже, чем byte[], он не использует кучу (поэтому почти не влияет на сборщик мусора), а загрузка/сохранение long сводится к одной инструкции машинного кода. Сегодня я проводил тест, записывая/читая 20 миллионов 17-байтовых обновлений в секунду. (с общей памятью) Насколько быстро вам это нужно? - person Peter Lawrey; 09.12.2011
comment
В моей системе это примерно в 30 раз быстрее, чем при использовании RandomAccessFile.read()/write(). - person Peter Lawrey; 09.12.2011
comment
Как насчет фрагментации? Если он не использует кучу Java GCed, я думаю, он использует какую-то другую кучу. И, возможно, он выгружается, так что 10-50 байт помещаются в 512-байтовые страницы или около того. Я немного сомневаюсь, но, возможно, я попробую. - person Mostowski Collapse; 09.12.2011
comment
В 30 раз быстрее, чем при использовании RandomAccessFile.read()/write(). --› так что у нас есть нижняя граница для наших потоков памяти... - person Mostowski Collapse; 09.12.2011
comment
Мне нужно хранить данные в течение недели, поэтому они выгружаются операционной системой. Размер страницы составляет 4 КБ на большинстве систем. - person Peter Lawrey; 09.12.2011
comment
Вы можете записать множество 50-байтовых обновлений на несколько ТБ дискового пространства. ;) - person Peter Lawrey; 09.12.2011
comment
Ах, я думаю, есть недоразумение. Для каждых 50 байт потребуется отдельный поток памяти. Этот поток памяти будет иметь 3-4 потока ввода/вывода в течение короткого времени, к которым будут обращаться несколько потоков, затем поток памяти полностью исчезнет. Но параллельно может быть >1000 объектов потока памяти или около того. - person Mostowski Collapse; 09.12.2011
comment
Потоки памяти — это банки, а байты — это файлы cookie. Будет много банок с коротким жизненным циклом. Привет от Печеньки-монстра. - person Mostowski Collapse; 09.12.2011
comment
Были ли это все RandomAccessFiles раньше?? Похоже, вам нужно изменить его. ;) Должны ли входные и выходные потоки быть многопоточными или каждый поток должен иметь свое собственное представление данных. Если каждый поток имеет размер 50 байт и является многопоточным, похоже, вы должны позволить сборщику мусора выполнить очистку. Вы можете использовать byte[] и создать оболочку для каждого входного и выходного потока. Будут значительные накладные расходы и мусор, но это не так плохо, как использование RandomAccessFile каждый. Кстати: передача крошечных фрагментов работы между потоками часто очень неэффективна, а использование одного потока может быть намного быстрее. - person Peter Lawrey; 09.12.2011

NIO позволяет напрямую передавать данные в памяти ядра - я не уверен, что он точно совпадает с потоком памяти .NET. вот простой пример отображения всего файла в памяти для чтения.

person Amir Afghani    schedule 08.12.2011
comment
не могли бы вы добавить код из внешней ссылки в свой ответ? - person Angelo Fuchs; 28.11.2014