似乎SqlFieldsQuery导致内存泄漏。我正在尝试测试Ignite.destroyCache方法,以确保在此方法之后清除所有缓存资源。但似乎当我们使用SqlFieldsQuery时,一些缓存资源没有被释放。
我写了很少的测试证明它。
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.Ignition;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.binary.BinaryObjectBuilder;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cluster.ClusterMetrics;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.junit.Test;
import java.util.Collections;
import java.util.UUID;
import java.util.stream.IntStream;
public class CacheDestroyTest {
private static final String BO_TEST = "bo_test";
@Test
public void shouldDestroyCacheAndFreeMemory() throws Exception {
IgniteConfiguration igniteCfg = new IgniteConfiguration();
igniteCfg.setGridName("CacheDestroyTest");
try (Ignite ignite = Ignition.start(igniteCfg)) {
for (int i = 0; i < 100; i++) {
CacheConfiguration<Integer, BinaryObject> cfg = new CacheConfiguration<>();
cfg.setQueryEntities(Collections.singletonList(queryEntity()));
cfg.setName("DestroyCacheAndFreeMemory_test" + i);
IgniteCache<Integer, BinaryObject> cache = ignite.getOrCreateCache(cfg);
IntStream.range(0, 200_000).parallel().forEach(id -> cache.put(id,
buildBinary(ignite.binary().builder(BO_TEST))));
cache.withKeepBinary().query(new SqlFieldsQuery("select * from " + BO_TEST + " limit 100")).getAll();
ignite.destroyCache(cache.getName());
System.out.println("Iteration " + i + " done");
ClusterMetrics metrics = ignite.cluster().metrics();
System.out.println("HeapMemoryTotal " + metrics.getHeapMemoryTotal() / 1024 / 1024);
System.out.println("HeapMemoryUsed " + metrics.getHeapMemoryUsed() / 1024 / 1024);
}
}
}
private QueryEntity queryEntity() {
QueryEntity entity = new QueryEntity();
entity.setKeyType(Integer.class.getName());
entity.setValueType(BO_TEST);
for (int i = 0; i < 20; i++) {
entity.addQueryField("data_" + i, String.class.getName(), null);
}
return entity;
}
private BinaryObject buildBinary(BinaryObjectBuilder builder) {
for (int i = 0; i < 20; i++) {
builder.setField("data_" + i, UUID.randomUUID().toString());
}
return builder.build();
}
public static void main(String[] args) throws Exception {
new CacheDestroyTest().shouldDestroyCacheAndFreeMemory();
}
}
我这次测试我在2次迭代后得到了java.lang.OutOfMemoryError(用-Xmx512m运行这个测试)。
Iteration 0 done
HeapMemoryTotal 498
HeapMemoryUsed 399
Iteration 1 done
HeapMemoryTotal 497
HeapMemoryUsed 484
没有线
cache.withKeepBinary().query(new SqlFieldsQuery("select * from " + BO_TEST + " limit 100")).getAll();
测试工作正常
Iteration 0 done
HeapMemoryTotal 498
HeapMemoryUsed 277
Iteration 1 done
HeapMemoryTotal 460
HeapMemoryUsed 328
Iteration 2 done
HeapMemoryTotal 455
HeapMemoryUsed 323
Iteration 3 done
HeapMemoryTotal 485
HeapMemoryUsed 316
Iteration 4 done
HeapMemoryTotal 504
HeapMemoryUsed 309
Iteration 5 done
HeapMemoryTotal 504
HeapMemoryUsed 300
我做错了什么或是错误? 我的Apache Ignite版本是1.8
UPD:
我在5次迭代后进行了堆转储。 疑似MAT问题: 由“sun.misc.Launcher $ AppClassLoader @ 0x6c18385f0”加载的“org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing”的一个实例占用1,083,398,360(80.77%)个字节。内存在“sun.misc.Launcher $ AppClassLoader @ 0x6c18385f0”加载的“org.apache.ignite.internal.processors.query.h2.IgniteH2Indexing $ StatementCache”的一个实例中累积。
答案 0 :(得分:1)
我将首先介绍您正在创建的二进制对象。 生成的RandomUUID长度为36个字符(至少在我的机器中)。这使得字符串的长度
(36 * 2(字节/字符)+(8 + 4 + 4)(java中字符串的开销))= 88字节。
此外,data_(int)字段名称还需要28个字节。
因此,一个二进制对象需要116个字节的数据。
所以,20个这样的二进制对象需要2320个字节。
现在,让我们考虑一个缓存条目: 值(20个二进制对象)需要2320个字节 密钥(整数)占用4个字节。
这为每个缓存条目提供了2324个字节。
因此,对于2,00,000(我从IntStream.range(0,200_000)推断)缓存条目所需的内存为464 MB。
现在,这不考虑Ignite本身和许多其他事情的开销。
我猜这就是Out of Memory异常的原因。
我假设Ignite Grid在一台机器上运行。