Подтвердить что ты не робот

Java из кучи во время сериализации

Следующий код вызывает OutOfMemmoryError: пустое место для примерно 3 миллионов строк. Память, выделенная для JVM, составляет 4 ГБ, с использованием 64-битной установки.

while (rs.next())
{

    ArrayList<String> arrayList = new ArrayList<String>();
    for (int i = 1; i <= columnCount; i++)
    {
        arrayList.add(rs.getString(i));
    }

    objOS.writeObject(arrayList);
}

Память, на которую ссылается ArrayList, имеет право на сбор мусора на каждой итерации цикла while, а внутренне JVM вызывает сбор мусора (System.gc()), прежде чем выбросить ошибку OutOfMemory из-за кучи.

Итак, почему возникает исключение?

4b9b3361

Ответ 1

Является objOS a ObjectOutputStream?

Если это так, то ваша проблема: ObjectOutputStream хранит сильную ссылку на каждый объект, который когда-либо был написан для этого, чтобы избежать записи одного и того же объекта дважды (он просто напишет ссылку, говорящую "этот объект, который я писал ранее с id x" ).

Это означает, что вы эффективно просачиваете все теги ArrayList.

Вы можете reset "кеш", вызвав reset() на ObjectOutputStream. Поскольку вы все равно не используете эту функцию, вы можете вызвать reset() непосредственно после вызова writeObject().

Ответ 2

Я согласен с @Joachim.

Ниже предложение было мифом

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

Истина
У меня есть отредактированный, потому что я чувствую, что может быть много людей, которые (как и я до сегодняшнего дня) все еще верят, что объявление объекта внутри цикла может нанести вред управлению памятью; что неверно. Чтобы продемонстрировать это, я использовал тот же код, который был отправлен на fooobar.com/info/31230/....
Ниже приведен фрагмент кода

package navsoft.advskill.test;

import java.util.ArrayList;

public class MemoryTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /* Total number of processors or cores available to the JVM */
        System.out.println("Available processors (cores): "
                + Runtime.getRuntime().availableProcessors());
        /*
         * Total amount of free memory available to the JVM
         */
        long freeMemory = Runtime.getRuntime().freeMemory();
        System.out.println("Free memory (bytes): "
                + freeMemory);
        /*
         * This will return Long.MAX_VALUE if there is no preset limit
         */
        long maxMemory = Runtime.getRuntime().maxMemory();
        /*
         * Maximum amount of memory the JVM will attempt to use
         */
        System.out.println("Maximum memory (bytes): "
                + (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));
        /*
         * Total memory currently in use by the JVM
         */
        System.out.println("Total memory (bytes): "
                + Runtime.getRuntime().totalMemory());
        final int LIMIT_COUNTER = 1000000;

        //System.out.println("Testing Only for print...");
        System.out.println("Testing for Collection inside Loop...");
        //System.out.println("Testing for Collection outside Loop...");
        //ArrayList<String> arr;
        for (int i = 0; i < LIMIT_COUNTER; ++i) {
            //arr = new ArrayList<String>();
            ArrayList<String> arr = new ArrayList<String>();
            System.out.println("" + i + ". Occupied(OldFree - currentFree): "+ (freeMemory - Runtime.getRuntime().freeMemory()));
        }
        System.out.println("Occupied At the End: "+ (freeMemory - Runtime.getRuntime().freeMemory()));
        System.out.println("End of Test");
    }

}

Результат вывода ясно показывает, что нет разницы в занятии/освобождении памяти, если вы либо объявляете объект внутри, либо вне цикла. Поэтому рекомендуется иметь декларацию как можно меньше. Я благодарю всех экспертов по StackOverflow (особенно @Miserable Variable) за то, что вы мне это посоветовали.

Надеюсь, это тоже уберет ваши сомнения.