Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Тест на OutOfMemoryError


Автор: MisterCleric 4.6.2009, 15:42
Привет всем. Кто что может сказать по данному поводу? Получил такой вопрос на собеседовании
Код

public class JavaMemoryPuzzlePolite {
    private int dataSize =
            (int) (Runtime.getRuntime().maxMemory() * 0.6);

    public void f() {
        {
            byte[] data = new byte[dataSize];
        }
//         int i=1;
        byte[] data = new byte[dataSize];
    }

    public static void main(String[] args) {
        JavaMemoryPuzzlePolite jmp = new JavaMemoryPuzzlePolite();
        jmp.f();
        System.out.println("No OutOfMemoryError");
    }
}


Если раскоментировать int i=1;, то OutOfMemoryError не будет.

Автор: math64 4.6.2009, 15:57
А врде так и так OutOfMemoryError не должно быть: при выделении второго data первый уже вне зоны видимости и может быть удалён сборщиком мусора.

Автор: hvzh 4.6.2009, 16:00
Судя по коду строка

System.out.println("No OutOfMemoryError");

будет выполняться всегда.

Кстати, одна скобка в коде явно лишняя

Автор: COVD 4.6.2009, 16:07
Держитесь подальше от придумывающих такие тесты - у них, похоже, нет реальных дел.  

Автор: MisterCleric 4.6.2009, 16:07
 smile Ребята. Надо сначала запустить и проверить, а потом уже говорить о том, что там лишнее и как оно выполняется
Вот код от сюда
http://www.javaspecialists.eu/archive/Issue173.html

Автор: COVD 4.6.2009, 16:18
Я проверял, компилятор это пропускает и все так , как вы описываете. Но я в первый раз вижу такую конструкцию (скобки внутри скобок). Наверное, это нормально для олимпиады по программированию, но на практике такое я точно использовать никогда не буду. Проще надо.

Автор: MisterCleric 4.6.2009, 16:20
понятно. Но вопрос заключался в том, почему после того, как мы раскоментируем объявление переменной, GC освобождает память, если нет, то вылазит знаменитый Exception

Автор: hvzh 4.6.2009, 16:49
Нда... Интересно...
Можно предположить, что при первом аллоцировании heap исчерпывается на 60% так что на второе памяти просто не хватает. Также следует отметить, что это аллоцирование происходит в своей области видимости и, следовательно, в момент второго аллоцирования память должна быть освобождена. Но вот почему это освобождение происходит только после объявления какой-либо переменной типа int i = 0; я тупо не знаю. Кстати, если код изменить следующим образом

Код

public class JavaMemoryPuzzlePolite {
    private int dataSize =
            (int) (Runtime.getRuntime().maxMemory() * 0.6);

    public void f() {
        byte[] data = new byte[dataSize];
        //         int i=1;
        byte[] data = new byte[dataSize];
    }


то ошибка выделения памяти будет генериться в любом случае

Автор: MisterCleric 4.6.2009, 16:56
Цитата

то ошибка выделения памяти будет генериться в любом случае 

ага. Потому, что GC еще не считает  byte[] data = new byte[dataSize]; уже недостижимой ссылкой.
А вот почему он в исходном случае не считает ее такой, эт уже вопрос...

Автор: COVD 4.6.2009, 17:06
Если пофантазировать, то получается, что локальная переменная (byte[] data во внутренних скобках) выбрасывается из стека (и, следовательно, становится доступной для GC) при добавлении чего-то в стек. Это происходит, например, при выполнении строки  int i=1; . Если же выполняется сразу byte[] data = new byte[dataSize]; , то тут сначала делается попытка выделить память (а локальная переменная все еще в стеке) , что и приводит к исключению. Наверное, это полезно знать и доктор Ханс этим примером показывает, почему надежнее обнулять переменные. Но все же на мой взгляд это академический нюанс.   
 

Автор: Fieral 4.6.2009, 18:04
внутренние скобки позволяют ограничить область видимости переменной -  иногда это удобно использовать.
например так:

Код

public void do(){
        ArrayList<Cool> A = new ArrayList<Cool>();

        {
            Cool C = new Cool();
            C.setName("N1");
            A.add(C);
        }
        {
            Cool C = new Cool();
            C.setName("N2");
            A.add(C);
        }
        {
            Cool C = new Cool();
            C.setName("N3");
            A.add(C);
        }
}


возможно это потомучто счетчик ссылок делает "i--" на выходе из scope (из зоны между скобками)

Автор: Kangaroo 4.6.2009, 23:48
Цитата(hvzh @  4.6.2009,  16:49 Найти цитируемый пост)
то ошибка выделения памяти будет генериться в любом случае 

Ага, ошибка компиляции  smile 


Цитата(Fieral @  4.6.2009,  18:04 Найти цитируемый пост)
внутренние скобки позволяют ограничить область видимости переменной -  иногда это удобно использовать.
например так:

Это - удобно ?!   smile 


По сабжу - я думал близко к последнему сообщению COVD. Но это так, наугад.

Автор: MisterCleric 5.6.2009, 09:48
Ну что ж: всем спасибо за участие в разборе такого вот интересного вопроса с памятью. Я тоже так думаю, что COVD где-то прав. 
Думаю можно ему дать плюсик за понимаение 
Цитата

академических нюансов

а мы будем ждать пояснений от доктора Ханса в следующем номере....

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)