трудно что-то сказать не видя всего кода. Но вот тут:
byte[] buffer = new byte[1000000000]; // RAM заюзалась
buffer = null;
buffer = new byte[100]; // (<b>GC</b>) тот же самый буфер. Но памяти при этом выделено под 1000000100 байт.
Нет никакой гарантии что сборщик мусора сработает. От может сработать, а может когда-нибудь потом.
Что происходит в этом коде? Вы выделяете память, buffer = null не говорит о том что память должна освободиться, а только что переменная ссылается на другой участок памяти (с адресом 0). Далее выделяете еще память и теперь переменная ссылается на новый участок памяти..
По поводу сборщика мусора. В 99,999% случаев, когда программисту хочется поработать вручную со сборщиком мусора, нужно править код.