我试图理解是什么保存了对对象的引用,使得它们在执行Java流终端操作时不符合垃圾收集的条件?
这是我的测试代码
import java.util.stream.IntStream;
import java.util.stream.Stream;
class Scratch {
public static void main(String[] args) {
Stream<LargeObject> objectStream = IntStream.rangeClosed(0, 1000000).mapToObj(LargeObject::new);
objectStream.peek(obj -> {
try {
Thread.sleep(1);
if (obj.i % 100 == 0) {
System.out.println("Processed: " + obj.i);
}
if (obj.i % 10000 == 0) {
System.out.println("Calling GC");
System.gc();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
})
.map(largeObject -> new Object())
.count();
}
private static class LargeObject {
private final int i;
private final byte[] alloc = new byte[1024];
private LargeObject(int i) {
this.i = i;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("" + i + " collected");
}
}
}
从未调用LargetObject的finalize方法。
我的想法是一旦. map(largeObject-
为什么这不会发生?也许真的可以做些什么?
这与最终确定和gc
无关。你应该提到你是在java-9
或更高版本(我想是的,但应该是这样)。我将简化这一点:
long howMany = List.of(1, 2, 3)
.stream()
.map(x -> {
System.out.println("mapping = " + x);
return x;
})
.count();
System.out.println(howMany);
由于初始流的大小是已知的,并且没有改变,因此根本不会执行peek
和map
(因此不会生成垃圾)。看看这个:
public static void main(String[] args) {
List<Integer> list = List.of(1, 2, 3);
Stream<Integer> one = isSized(list.stream());
Stream<Integer> two = isSized(one.map(x -> {
System.out.println("mapping = " + x);
return x;
}));
long count = isSized(two).count();
System.out.println(count);
}
private static Stream<Integer> isSized(Stream<Integer> stream) {
Spliterator<Integer> sp = stream.spliterator();
System.out.println(sp.hasCharacteristics(Spliterator.SIZED));
return StreamSupport.stream(sp, stream.isParallel());
}
用java-8编译相同的代码,你会看到不同的画面。
问题内容: 是什么决定了垃圾收集器何时真正收集?它是在一定时间之后还是在一定数量的内存用完之后发生的吗?还是还有其他因素? 问题答案: 它在确定是时候运行时运行。在世代垃圾收集器中,一种常见的策略是在第0代内存分配失败时运行收集器。也就是说,每次你分配一小块内存(大块通常直接放置在“旧”代中)时,系统都会检查gen-0堆中是否有足够的可用空间,如果没有,则运行GC释放空间以使分配成功。然后将旧数据
有人能给我解释一下原因吗?
问题内容: 我经常读到,在Sun JVM中,短寿命对象(“相对较新的对象”)比长寿命对象(“相对较旧的对象”)可以更有效地进行垃圾回收。 为什么呢? 这是特定于Sun JVM还是由一般的垃圾回收原理导致? 问题答案: 大多数Java应用程序都会创建Java对象,然后很快将其丢弃。您可以在方法中创建一些对象,然后一旦退出该方法,所有对象都会死亡。大多数应用程序都是以这种方式运行的,并且大多数人倾向于
[GC(分配失败)[defnew:10931K->472K(12288K),0.0053905秒]10931K->10712K(39616K),0.0054285秒][times:user=0.00 sys=0.00,real=0.01秒] [GC(分配失败)[defnew:10712k->472k(12288k),0.0057686秒]20952k->20952k(39616k),0.00580
问题内容: 我对可以控制CMS收集器启动时间的两个参数感到困惑: (默认为70%) (默认情况下超过90%) 这些参数的确切含义是什么?收集器什么时候开始(标记阶段)并收集(清扫阶段)? 问题答案: 决定何时启动CMS(为了使此选项生效,您还必须设置)。是确定世代空间大小的选项。 参见例如… http://java.sun.com/docs/hotspot/gc1.4.2/faq.html 通常无
来自MSDN:“当一个对象不可访问时,垃圾收集器会将该对象视为垃圾。然后,当垃圾收集器将一个对象的条目从终结队列移动到freachable队列时,该对象不再被视为垃圾,其内存也不会被回收。此时,垃圾收集器已完成对垃圾的识别。一些被识别为垃圾的对象已被重新分类。”被归类为非垃圾。垃圾收集器压缩可回收内存,特殊运行时线程清空可回收队列,执行每个对象的Finalize方法。需要两个GC来回收需要终结的对