Хобрук: Ваш путь к мастерству в программировании

Java DataOutputStream/DataInputStream OutOfMemoryError

Я пытаюсь отправить массив байтов, содержащий 16 элементов, через сокеты, используя DataOutputStream на клиенте и DataInputStream на сервере.

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

public void sendBytes(byte[] myByteArray) throws IOException {
    sendBytes(myByteArray, 0, myByteArray.length);
}

public void sendBytes(byte[] myByteArray, int start, int len) throws IOException {
    if (len < 0)
        throw new IllegalArgumentException("Negative length not allowed");
    if (start < 0 || start >= myByteArray.length)
        throw new IndexOutOfBoundsException("Out of bounds: " + start);     
    dOutput.writeInt(len);
    if (len > 0) {
        dOutput.write(myByteArray, start, len);
        dOutput.flush();
    }       
}

public byte[] readBytes() throws IOException {
    int len = dInput.readInt();
    System.out.println("Byte array length: " + len); //prints '16'
    byte[] data = new byte[len];
    if (len > 0) {
        dInput.readFully(data);
    }
    return data;
}

Все работает нормально, и я могу напечатать длину массива байтов, массив байтов (зашифрованный текст), а затем расшифровать массив байтов и распечатать исходный открытый текст, который я отправил, но сразу после его печати в консоли программа вылетает с ошибкой OutOfMemoryError: Java heap space .

Я читал, что обычно это происходит из-за того, что DataOutputStream не очищается, но я вызываю его внутри метода sendBytes, поэтому он должен очищать его после отправки каждого массива.

Компилятор сообщает мне, что ошибка возникает внутри readBytes в строке byte[] data = new byte[len];, а также там, где я вызываю readBytes() в основном методе.

Любая помощь будет оценена!

Изменить

На самом деле я получаю некоторые неожиданные результаты.

17:50:14 Server waiting for Clients on port 1500. Thread trying to create Object Input/Output Streams 17:50:16 Client[0.7757499147242042] just connected. 17:50:16 Server waiting for Clients on port 1500. Byte array length: 16 Server recieved ciphertext: 27 10 -49 -83 127 127 84 -81 48 -85 -57 -38 -13 -126 -88 6 Server decrypted ciphertext to: asd 17:50:19 Client[0.7757499147242042] Byte array length: 1946157921

Я вызываю readBytes() в цикле while, поэтому сервер будет прослушивать все, что передается через сокет. Я предполагаю, что он пытается запустить его во второй раз, хотя ничего больше не было отправлено, а переменная len каким-то образом установлена ​​​​на 1946157921. Какая логика может стоять за этим?


  • вы предъявляете иск, что вы передаете длину байта ?? 31.05.2014
  • len слишком велик для доступной памяти. Попробуйте вывести его перед выделением массива байтов, чтобы увидеть, сколько байтов вы запрашиваете. 31.05.2014
  • Вы отлаживали и смотрели, что делает gc()? 31.05.2014
  • Выведите len в строке перед ошибкой. Было бы очень полезно, если бы вы показали короткую, но полную программу, демонстрирующую проблему. 31.05.2014
  • @ Генри, я вывожу это. Лен всегда = 16 31.05.2014
  • Это, вероятно, не решит загадку, но это всегда хороший подход, чтобы процитировать Stacktrace, если это произойдет, и отметить строку в коде, где она начинается;) 31.05.2014
  • 1946157921 святая мать байтов, это много .. Я думаю, вы вводите неправильный целочисленный байт 31.05.2014

Ответы:


1

Вы должны отправлять что-то еще через сокет; не читать его так, как вы его написали; и так выходит из синхронизации. Эффект будет заключаться в том, что вы читаете длину, которая не является реальной длиной; слишком большой; и заканчивается память, когда вы пытаетесь ее выделить. Ошибка не в этом коде. За исключением, конечно, того, что если len == 0, вы не должны выделять массив пока при чтении.

Я читал, что это обычно из-за того, что DataOutputStream не очищается.

Это не так.

Переменная len каким-то образом устанавливается на 1946157921.

Как и предсказывалось. КЭД

31.05.2014
  • Ты прав. Я отправлял объект через сокет также другим методом. Я не знал, что использование как ObjectOutputStreams, так и DataOutputStreams вызовет проблемы с чтением/записью в сокете. 31.05.2014
  • В этом нет необходимости, но использование нескольких потоков на сокет чревато трудностями, и их лучше избегать. 31.05.2014

  • 2

    У вас заканчивается доступная куча. Быстрым решением для этого будет увеличение (или указание отсутствия) параметра -Xmx в параметрах запуска JVM до уровня, на котором приложение может выполнить поставленную задачу.

    01.06.2014

    3

    Запустите свое приложение с помощью -Xms1500m в консоли, в Netbeans вы можете найти его в свойствах проекта->Выполнить->Параметры виртуальной машины.

    Сегодня я столкнулся с этой проблемой нехватки памяти, и после настройки Xms я смог решить эту проблему. Проверьте, работает ли это с вами, если есть что-то действительно большее, чем это, вам придется проверить, как вы можете улучшить свой код.

    Проверьте обсуждение здесь

    31.05.2014
  • Я попробую сейчас. Что именно это делает? 31.05.2014
  • Вы хотите предложить настройку Xmx, которая увеличивает максимальное пространство кучи. 31.05.2014
  • Таким образом вы настраиваете использование памяти JVM, вы также можете попробовать -Xmx и попытаться увеличить размер. Думаю, не уверен, в win32 можно использовать до 2Гб. 31.05.2014
  • @TimBender, по крайней мере, у меня сегодня это сработало. У меня возникла проблема с ArrayList, когда я добавлял снимок, сделанный Java Robot. 31.05.2014
  • @Raj См.: docs.oracle.com/cd/ E13150_01/jrockit_jvm/jrockit/jrdocs/refman/ Возможно, Netbeans хорошо к вам относится и устанавливает для вас Xmx, но обычно Xms (минимальный размер) не может превышать Xmx (максимальный размер). 02.06.2014
  • @TimBender, извините, что не упомянул -Xmx. Мы можем держать обоих равными. Xms Размер, который он требует при запуске, и Xmx максимальный размер, который, я думаю, теоретически может достигать 4 ГБ в 32-битной оконной системе. 02.06.2014
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

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

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..