JIT создаёт для горячего метода задачу CompileTask: она держит ссылку на метод, класс и его загрузчик. Пока поток C1 или C2 не завершит компиляцию, GC не выгрузит загрузчик.
Поэтому тест после
System.gc() может срабатывать нестабильно. Повторный полный GC иногда мешает компиляторам закончить работу.Для диагностики дайте JIT время либо отключите фоновую компиляцию флагом
-XX:-BackgroundCompilation. Это делает удаление задач предсказуемее, но добавляет скачки задержки. Тест с URLClassLoader и PhantomReference показывает этот сценарий.