Почему FileOutputStream не выбрасывает OutOfMemoryException - PullRequest
2 голосов
/ 18 июля 2010

Я попробовал приведенный ниже код как для Windows (64-разрядная версия), так и для Linux (32-разрядная версия).

Я был уверен, что без BufferedOutputStream код должен генерировать исключение OutOfMemoryException, но это не так.

Почему это? Кто там делает {caching / buffer / steaming} на диск?

Не могли бы вы описать, если нужно, полный ответ (Java API -> системный вызов)?

Использует ли этот код NIO?

/ Я в замешательстве.

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class WriteHugeFileToDisk {
    private static int BYTE = 1;
    private static int KILBYTE = BYTE * 1024;
    private static int MEGABYTE = KILBYTE * 1024;
    private static int GIGABYTE = MEGABYTE * 1024;
    private static long TERABYTE = GIGABYTE * 1024L;

    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(args[0]);
        DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

        byte[] buffer = new byte[MEGABYTE];
        for(int i = 0; i < buffer.length; i++) {
            buffer[i] = (byte)i;
        }

        for(long l = 0; l < 4000; l++) {
            dataOutputStream.write(buffer);
            ;
        }

    }
}

Я запустил этот код с Java 6. Используя следующие вызовы:

Windows

java WriteHugeFileToDisk %TEMP%\hi.txt

Linux:

java WriteHugeFileToDisk /mnt/hi.info

Обратите внимание: код создает файл объемом 4 ГБ, заполненный только для теста.

Ответы [ 4 ]

5 голосов
/ 18 июля 2010

Зачем ему выбрасывать OutOfMemoryException?Это просто запись на диск.Я не удивлюсь, если бы FileOutputStream и DataOutputStream имели некоторую буферизацию (я не проверял), но они, конечно, не обязаны буферизовать все , что вы пишете.

Этот код не использует NIO напрямую, хотя я не удивлюсь, если некоторые из внутренних вещей сделали.Что касается того, какие системные вызовы задействованы, и когда - это будет зависеть от реализации, но важно понимать, что ни DataOutputStream, ни FileOutputStream не предназначены для буферизации всего.Вы записываете в них некоторые данные, и некоторые из этих данных могут записываться на диск.Если вы сбрасываете или закрываете поток, это должно сделать все записанными вами данными на диск.Если вы не не очистите или не закроете поток, я бы ожидал, что будет кэшировано только достаточно небольшое количество (опять же, зависящее от реализации), если оно есть.

Обратите внимание, что BufferedOutputStream действительно вводит кэширование - но только столько, сколько вы просите (или по умолчанию).Опять же, он не будет буферизовать все , если вы не запросите столько буфера, сколько пишете в терминах данных.

1 голос
/ 19 июля 2010

Кто там делает {caching / buffer / steaming} на диске?

Nobody. Он пишет прямо на диск. Никакого дополнительного использования памяти.

1 голос
/ 18 июля 2010

Эти две инструкции почти не занимают память и открывают дескриптор файла.

FileOutputStream fileOutputStream = new FileOutputStream(args[0]);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

Выделите и заполните 1 МБ данных массив байтов, который хранится в памяти.

byte[] buffer = new byte[MEGABYTE];
for(int i = 0; i < buffer.length; i++) {
    buffer[i] = (byte)i;
}

Записать в выходной файл 4000 раз этот 1 МБ данных.

for(long l = 0; l < 4000; l++) {
    dataOutputStream.write(buffer);
}

Вывод: 1 МБ памяти занято и 4 ГБ данных записано в файл. Так что, если у вас очень мало памяти, это не может выбросить OutOfMemoryException.

1 голос
/ 18 июля 2010

Буферизованный поток - это потоковая оболочка, которая (вполне очевидно) буферизует данные в памяти перед передачей их в базовый поток.Это дает вам лучшую производительность при использовании в сочетании с файловым потоком, потому что при чтении или записи на жесткий диск приходится много накладных расходов.Буферизация позволяет значительно сократить количество операций чтения / записи, сворачивая в противном случае неэффективные множественные операции чтения или записи в одну, более эффективную, большую.Тем не менее, это не критично для хорошего поведения вашего приложения.Это просто поможет вам сделать меньше обращений к физическим устройствам.

Java не имеет более прямого доступа к устройствам вашего компьютера, чем другие языки.Между вашей программой и битами на вашем жестком диске все еще есть несколько уровней, которые имеют право буферизовать или кэшировать все, что Java отчаянно пытается получить с диска или на диск.Насколько я знаю, ОС может (и обычно будет) кешировать или буферизовать содержимое, а некоторые аппаратные средства тоже будут это делать.или сбой чтения или записи на устройства или, в этом отношении, в любой поток.

...