JIT可以做这个字段访问优化吗? [英] Can JIT do this field access optimization?

查看:105
本文介绍了JIT可以做这个字段访问优化吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

免责声明:请不要咨询有关过早优化的建议。我只是好奇。



想象一下,我想确保某个字段引用的某些对象可以尽快垃圾收集。我使用了一个像这样的自制链接列表

  class BigData {
byte [] someBigArray;
BigData接下来;
}

私人BigData bigData;

并像这样迭代

  while(bigData!= null){
process(bigData);
bigData = bigData.next;
}

JIT是否可以像下面那样自由更改它?

  BigData tmp = bigData; 
while(tmp!= null){
process(tmp);
tmp = tmp.next;
}
bigData = null;

假设没有其他任何对 BigData 。假设 process 是一个简单的可内联方法,不访问字段 bigData 。这两个代码片段是等价的(假设没有任何异常被抛出),唯一的区别是第二个代码将字段访问从循环移动到了外部。



重申免责声明:请不要提出有关过早优化的建议。我只是好奇。

想'就是JIT所做的事情,为什么会让GC快速收集它们?:如果JIT执行了更改,那么所有大对象只能在循环之后收集。如果没有,那么每次循环前进一个对象就有资格获得GC。



附录:



<实际上,只要JIT可以自由地进行上述转换,它就可以做到这一点:

  BigData tmp = bigData ; 
bigData = null;
while(tmp!= null){
process(tmp);
tmp = tmp.next;
}

这里我看不到任何缺点,它会尽快收集所有对象如原始代码所示。

解决方案

好的,优化器可以优化

  while(bigData!= null){
process(bigData);
bigData = bigData.next;
}

转换为

  BigData tmp = bigData; 
while(tmp!= null){
process(tmp);
tmp = tmp.next;
}
bigData = null;

如果 bigData 字段不是 volatile process 方法没有任何副作用,禁止这种优化。



但实际上,代码转换(如果有的话)看起来完全不同。通常情况下,优化器会循环展开,创建一个执行一定次数迭代的代码块,并在进行向后跳转之前执行现场存储操作。因此,垃圾收集器可以跳转到某些保存点。但如果过程方法包含访问 bigData 字段或可能分配内存等,现场存储将在每次调用之前执行。


Disclaimer: Please no advice concerning premature optimization. I'm just curious.

Imagine I want to make sure that some objects referenced by a field can be garbage collected ASAP. I'm using a home-made singly linked list like this

class BigData {
    byte[] someBigArray;
    BigData next;
}

private BigData bigData;

and iterate like this

while (bigData != null) {
    process(bigData);
    bigData = bigData.next;
}

Is the JIT free to change it like follows?

BigData tmp = bigData;
while (tmp != null) {
    process(tmp);
    tmp = tmp.next;
}
bigData = null;

Assume there's no other reference to any instance of BigData. Assume process is a simple inlineable method not accessing the field bigData. Both snippets are equivalent (assuming no exception gets thrown in between), the only difference is that the second moves the field access from the loop to the outside.

Disclaimer repeated: Please no advice concerning premature optimization. I'm just curious.


To answer the comment "Even if the change you 'want' is what the JIT does, why would that make the GC collect them faster/sooner?": If the JIT does the change, then that all the big objects can be only collected after the loop. If it doesn't, then each time the loop advances one more object becomes eligible for GC.

Addendum:

Actually, whenever the JIT is free to do the above transform, it can do this one instead:

BigData tmp = bigData;
bigData = null;
while (tmp != null) {
    process(tmp);
    tmp = tmp.next;
}

I can't see any disadvantage here and it makes all objects collectible as soon as in the original code.

解决方案

Well, the optimizer can optimize

while (bigData != null) {
    process(bigData);
    bigData = bigData.next;
}

into

BigData tmp = bigData;
while (tmp != null) {
    process(tmp);
    tmp = tmp.next;
}
bigData = null;

if the bigData field is not volatile and the process method has no side-effects that forbid this optimization.

But in practice, the code transformation, if any, will look completely different. It’s typical that optimizers do loop unrolling, creating a code block performing a certain number of iterations and do the field storage operation before taking a backwards jump. So there are certain "savepoints" where the garbage collector can jump in. But if the process method contains code that accesses the bigData field or might allocate memory, etc, the field storage will be performed before every invocation.

这篇关于JIT可以做这个字段访问优化吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆