G1 不处理软引用
G1 doesn't process soft references
这是我的简单 gc 测试:
public class Main {
static class Data {
public long[] l = new long[100];
}
static List<SoftReference<Data>> list = new ArrayList<>();
public static void main(String[] args) {
long i = 0;
while (true) {
list.add(new SoftReference<>(new Data()));
++i;
if (i % 1000 == 0) {
sleep(1);
if (i % 1_000_000 == 0)
sleep(1000);
}
}
}
static void sleep(long millis) {
try { Thread.sleep(millis); } catch (InterruptedException ignored) {}
}
}
使用这些参数(启用 G1):
java -Xmx2G -Xms2G -XX:MaxPermSize=128m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-XX:+PrintAdaptiveSizePolicy -Xloggc:jvm.log -XX:+UseG1GC
-XX:InitiatingHeapOccupancyPercent=5 Main
我 grep 输出:
grep -E "(Full|GC cleanup)" jvm.log
得到这样的东西:
0.564: [GC cleanup 277M->277M(2048M), 0.0009922 secs]
0.879: [GC cleanup 443M->442M(2048M), 0.0009396 secs]
1.676: [GC cleanup 859M->856M(2048M), 0.0008681 secs]
3.530: [GC cleanup 1324M->1320M(2048M), 0.0012422 secs]
4.838: [GC cleanup 1711M->1707M(2048M), 0.0010601 secs]
6.334: [Full GC 2047M->102M(2048M), 1.2659685 secs]
8.322: [GC cleanup 534M->534M(2048M), 0.0009528 secs]
11.250: [GC cleanup 1460M->1450M(2048M), 0.0011207 secs]
13.499: [Full GC 2046M->512M(2048M), 1.3534848 secs]
似乎软引用是在ParallelGc 的完整收集期间收集的,而并发收集几乎没有用。来自 VisualVm 的堆转储也证明了这个版本。
我是不是遗漏了什么或者是 G1 中的错误?
检查 1.7.0_51-b13 和 1.8.0_45-b15 x64.
也许您对弱引用感到困惑?
GC 不会强制收集软引用,除非它发现自己处于严重的内存压力下。
有关详细信息,请参阅 here。
请特别注意文档中的以下引用:
Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand.
文档提供的唯一真正保证如下:
All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.
有 -XX:SoftRefLRUPolicyMSPerMB=
(默认值=1000)控制软引用的收集率。较低的值使其收集速度更快。
我不知道它是如何与G1的地区互动的。有可能某些区域很少被触及,因此它们的软引用没有被考虑在内。
正如@sstan 提到的那样,WeakReferences 可能会以更短的引用生命周期为代价提供更可预测的行为。
另一个问题是您没有清除无效软引用对象列表。如果你用 reference queue 注册引用,在睡眠(1000)之后轮询该队列以获取引用并将它们从列表中删除,你不应该 运行 内存不足。
为了更快地查找,集合可能比列表更合适。
这是我的简单 gc 测试:
public class Main {
static class Data {
public long[] l = new long[100];
}
static List<SoftReference<Data>> list = new ArrayList<>();
public static void main(String[] args) {
long i = 0;
while (true) {
list.add(new SoftReference<>(new Data()));
++i;
if (i % 1000 == 0) {
sleep(1);
if (i % 1_000_000 == 0)
sleep(1000);
}
}
}
static void sleep(long millis) {
try { Thread.sleep(millis); } catch (InterruptedException ignored) {}
}
}
使用这些参数(启用 G1):
java -Xmx2G -Xms2G -XX:MaxPermSize=128m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-XX:+PrintAdaptiveSizePolicy -Xloggc:jvm.log -XX:+UseG1GC
-XX:InitiatingHeapOccupancyPercent=5 Main
我 grep 输出:
grep -E "(Full|GC cleanup)" jvm.log
得到这样的东西:
0.564: [GC cleanup 277M->277M(2048M), 0.0009922 secs]
0.879: [GC cleanup 443M->442M(2048M), 0.0009396 secs]
1.676: [GC cleanup 859M->856M(2048M), 0.0008681 secs]
3.530: [GC cleanup 1324M->1320M(2048M), 0.0012422 secs]
4.838: [GC cleanup 1711M->1707M(2048M), 0.0010601 secs]
6.334: [Full GC 2047M->102M(2048M), 1.2659685 secs]
8.322: [GC cleanup 534M->534M(2048M), 0.0009528 secs]
11.250: [GC cleanup 1460M->1450M(2048M), 0.0011207 secs]
13.499: [Full GC 2046M->512M(2048M), 1.3534848 secs]
似乎软引用是在ParallelGc 的完整收集期间收集的,而并发收集几乎没有用。来自 VisualVm 的堆转储也证明了这个版本。
我是不是遗漏了什么或者是 G1 中的错误?
检查 1.7.0_51-b13 和 1.8.0_45-b15 x64.
也许您对弱引用感到困惑?
GC 不会强制收集软引用,除非它发现自己处于严重的内存压力下。
有关详细信息,请参阅 here。
请特别注意文档中的以下引用:
Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand.
文档提供的唯一真正保证如下:
All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.
有 -XX:SoftRefLRUPolicyMSPerMB=
(默认值=1000)控制软引用的收集率。较低的值使其收集速度更快。
我不知道它是如何与G1的地区互动的。有可能某些区域很少被触及,因此它们的软引用没有被考虑在内。
正如@sstan 提到的那样,WeakReferences 可能会以更短的引用生命周期为代价提供更可预测的行为。
另一个问题是您没有清除无效软引用对象列表。如果你用 reference queue 注册引用,在睡眠(1000)之后轮询该队列以获取引用并将它们从列表中删除,你不应该 运行 内存不足。 为了更快地查找,集合可能比列表更合适。