div.main {margin-left: 20pt; margin-right: 20pt}А где же память?
О некоторых особенностях работы сборщика мусора (garbage collector, gc)
в Sun JDK 1.2.2 и IBM JDK 1.3.0.
Как известно, сборщик мусора в виртуальной Ява-машине - это параллельный
процесс с низким приоритетом. Он выполняется одновременно с программой
пользователя и добавляет к свободной памяти участки хипа, на которые никто не
ссылается. Возникает резонный вопрос - что будет, если программа начнет
интенсивно выделять память на относительно короткий срок? Успеет ли сборщик
мусора "вычистить мусор"? Рассмотрим следующий пример (он должен находиться в
файле TestGC.java): class Elem
{
int h[];
Elem() { h = new int[100000]; }
public void finalize() { System.out.print("finalize() "); }
} public class TestGC
{ public static void Oops() throws Exception {
throw new Exception("Test");
} public static void main(String[] arg) {
int dummy = 1;
for (int i = 0; i < 100000; i++)
{
try {
Elem elem;
elem = new Elem();
if (dummy == 1) Oops();
}
catch(Exception e) {
// System.gc();
System.out.print("" + i + " ");
}
}
}
} В примере в цикле происходит выделение нового экземпляра
объекта Elem (размером около 400 Кбайт). Сразу после этого "бросается"
исключение и мы, разумеется, теряем указатель на этот новый объект. Следуя
логике java этот объект тут же превращается в "мусор", который следует
"чистить". Откомпилируем данный пример и запустим его с ограничением размера
динамической памяти 20 Mb. Это делается так :
java -Xms1Mb -Xmx20Mb TestGC
Под Sun JVM можно наблюдать следующее поведение: через какое-то время
происходит исключение OutOfMemory (нехватка памяти). Под IBM JVM такого не
происходит. Объяснение этому может быть такое: в случае, когда при выделении
памяти ее не хватает, IBM JVM приостанавливает все процессы и принудительно
вызывает сборщик мусора. Тот высвобождает память, достаточную для нового объекта
и программа продолжает выполнение. Это очень разумное поведение, которое и
ожидаешь в данном случае. Для Sun JVM дела обстоят не так радостно. Очевидно,
что Sun JVM не пытается особым образом обработать случай нехватки памяти и для
программ, интенсивно использующих память, остается один выход - самим вызывать
сборщик мусора (System.gc()) в критических местах. Если откомментарить строчку с
данным вызовом в вышеуказанном примере, то поведение программы становится
абсолютно предсказуемым - сразу после появления "мусора", он "вычищается". Можно
так же устанавливать и ожидание треда через sleep, тогда при нехватке памяти
gc() все таки будет вызываться. В противном случае главный тред не даст
выполниться треду gc() и возникнет исключение о нехватке памяти.
|