gpt4 book ai didi

java - 防止Java 7过早发生GC

转载 作者:行者123 更新时间:2023-11-30 04:28:35 26 4
gpt4 key购买 nike

Can JIT be prevented from optimising away method calls?相似,我试图跟踪长期存在的数据存储对象的内存使用情况,但是我发现,如果我初始化一个存储,记录系统内存,然后初始化另一个存储,有时是编译器(大概是JIT) )足够聪明,可以注意到不再需要这些对象。

public class MemTest {
public static void main(String[] args) {
logMemory("Initial State");
MemoryHog mh = new MemoryHog();
logMemory("Built MemoryHog");
MemoryHog mh2 = new MemoryHog();
logMemory("Built Second MemoryHog"); // by here, mh may be GCed
}
}


现在,链接线程中的建议是保留指向这些对象的指针,但是GC似乎很聪明,可以告诉 main()不再使用这些对象。我可以在上一个 logMemory()调用之后添加对这些对象的调用,但这是一种相当手动的解决方案-每次测试一个对象时,我都必须在最后一个 logMemory()调用之后进行某种副作用触发调用,否则我可能会得到不一致的结果。

我正在寻找一般案例解决方案;我知道在 System.out.println(mh.hashCode()+mh2.hashCode())方法末尾添加像 main()这样的调用就足够了,但是出于某些原因,我不喜欢这样做。首先,它引入了上述测试的外部依赖性-如果删除了SOUT调用,则在内存记录调用期间JVM的行为可能会更改。其次,它容易出现用户错误;如果上面测试的对象发生了更改,或者添加了新对象,则用户必须记住也要手动更新此SOUT调用,否则它们将在测试中引入难以检测到的不一致之处。最后,我完全不喜欢打印此解决方案-似乎可以通过更好地理解JIT优化来避免不必要的黑客攻击。最后一点,Patricia Shanahan的答案提供了一个合理的解决方案(明确显示输出是出于记忆理智的目的),但我仍然希望尽可能避免这种情况。

因此,我最初的解决方案是将这些对象存储在静态列表中,然后在主类的finalize方法*中对其进行迭代,如下所示:

public class MemTest {
private static ArrayList<Object> objectHolder = new ArrayList<>();

public static void main(String[] args) {
logMemory("Initial State", null);
MemoryHog mh = new MemoryHog();
logMemory("Built MemoryHog", mh); // adds mh to objectHolder
MemoryHog mh2 = new MemoryHog();
logMemory("Built Second MemoryHog", mh2); // adds mh2 to objectHolder
}

protected void finalize() throws Throwable {
for(Object o : objectHolder) {
o.hashCode();
}
}
}


但是现在,我只将问题转移了一个步骤-如果JIT在finalize方法中优化了循环,并决定不需要保存这些对象该怎么办?诚然,对于Java 7来说,简单地将对象保留在主类中就足够了,但是除非有文献证明finalzie方法无法进行优化,否则从理论上讲,仍然没有任何东西可以阻止JIT / GC尽早摆脱这些对象,因为我的finalize方法的内容没有任何副作用。

一种可能是将finalize方法更改为:

protected void finalize() throws Throwable {
int codes = 0;
for(Object o : loggedObjects) {
codes += o.hashCode();
}
System.out.println(codes);
}


据我了解(这里我可能是错的),调用 System.out.println()将防止JIT删除此代码,因为它是一种具有外部副作用的方法,因此即使它不影响程序,它也可以不会被删除。这是有前途的,但是如果可以的话,我真的不希望输出任何乱码。 JIT无法(或不应该!)优化掉 System.out.println()调用这一事实向我暗示了JIT具有副作用的概念,如果我能告诉它这个finalize块具有此类副作用,它应该永远不要优化它。

所以我的问题是:


holdijng是否足以在主类中列出对象列表,以防止它们被垃圾回收?
遍历这些对象并在finalize方法中调用诸如 .hashCode()这样的琐碎事情就足够了吗?
用这种方法计算和打印一些结果是否足够?
JIT知道还有其他方法(例如 System.out.println)无法优化,甚至更好吗,是否有某种方法告诉JIT不要优化方法调用/代码块?


*一些快速测试证实了,正如我所怀疑的那样,JVM通常不会运行主类的finalize方法,而是突然退出。 JIT / GC可能仍然不够聪明,不能仅仅因为finalize方法存在而就可以对我的对象进行GC,即使它无法运行,但我不确定情况总是如此。如果这不是记录在案的行为,我将无法合理地相信它会保持真实,即使现在是真实的。

最佳答案

这是一个计划,可能有些大材小用,但是应该是安全且相当简单的:


保留对对象的引用列表。
最后,遍历列表,对hashCode()结果求和。
打印哈希码的总和。


打印总和可确保无法优化最终循环。对于每个对象创建,您唯一需要做的就是将其放入List add调用中。

关于java - 防止Java 7过早发生GC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15193878/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com