AtomicXXXFieldUpdater在内存优化中的是实战
1. 背景
在很多项目中例如 Netty、druid、DLedger
中都能看到 AtomicXXXFieldUpdater
的身影,例如在Netty的 HashedWheelTimer
类中就有 AtomicIntegerFieldUpdater
代码的存在。又比如在druid中的PR-165。大量的试用了AtomicXXXFieldUpdater
这一类相似的类。AtomicXXXFieldUpdater表示的是一系列类:
- AtomicIntegerFieldUpdater
- AtomicLongFieldUpdater
- AtomicReferenceFieldUpdater
今天就来聊聊 AtomicXXXFieldUpdater
在内 存优化中的实战,下面在笔者在 DLedger(RocketMQ的一个组件) 中对内存的优化,对应的ISSUE#189和PR-190
2. 案例说明
首先我们看一下这样的例子:
public class AtomicIntegerTest {
final AtomicInteger startPosition = new AtomicInteger(0);
final AtomicInteger wrotePosition = new AtomicInteger(0);
final AtomicInteger committedPosition = new AtomicInteger(0);
final AtomicInteger flushedPosition = new AtomicInteger(0);
public static void main(String[] args) throws Exception{
List<AtomicIntegerTest> list = new LinkedList<>();
for (int i = 0; i < 1000000; i++) {
list.add(new AtomicIntegerTest());
}
System.out.println("create instances 1000000");
System.in.read();
}
}
然后使用 YourKit tools
工具进行分析(也可以使用其他的分析工具)。
从上图可以看出来**AtomicInteger
** 大概占用了64M。而AtomicIntegerTest对象实例整个占用了96M.
然后用AtomicIntegerFieldUpdater
进行改造,如下例子:
public class AtomicIntegerFieldUpdaterTest {
public static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> startPosition = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"startPositionInt");
public static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> wrotePosition = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"wrotePositionInt");
public static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> committedPosition = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"committedPositionInt");
public static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> flushedPosition =AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"flushedPositionInt");
private volatile int startPositionInt = 0;
private volatile int wrotePositionInt = 0;
private volatile int committedPositionInt = 0;
private volatile int flushedPositionInt = 0;
public static void main(String[] args) throws Exception{
List<AtomicIntegerFieldUpdaterTest> list = new LinkedList<>();
for (int i = 0; i < 1000000; i++) {
list.add(new AtomicIntegerFieldUpdaterTest());
}
System.out.println("create instances 1000000");
System.in.read();
}
}
使用使用 YourKit tools
工具进行分析结果如下:
AtomicIntegerFieldUpdaterTest整个对象大小的和为32M,相比之前的总共小了64M。大大的减少了内存的开销。
然后笔者对DLedger项目的DefaultMmapFile进行优化最终被Merge:
3. AtomicXXXFieldUpdater如何使用
- AtomicXXXFieldUpdater必须是静态变量
- 被更新的变量必 须被关键字volatile修饰
例子如下:
public class AtomicIntegerFieldUpdaterTest {
public static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> startPosition = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class,"startPositionInt");
private volatile int startPositionInt = 0;
}