我尝试使用 Kryo 序列化程序将 Employee 对象保存到 EHCache 的堆外层,但它比我尝试在不使用 Kryo 序列化程序的情况下保存它时占用的空间更多。我在下面提供了代码片段和层统计信息。 有什么建议为什么会这样吗?
Kryo 的层级统计
tierStats=[TierStats(tierName=OffHeap, allocatedByteSize=6094848, occupiedByteSize=4184000, evictions=0, expirations=0, hits=0, misses=0, mappings=1000, puts=0, removals=0)])
没有 Kryo 的层级统计
tierStats=[TierStats(tierName=OffHeap, allocatedByteSize=4259840, occupiedByteSize=119200, evictions=0, expirations=0, hits=0, misses=0, mappings=1000, puts=0, removals=0)])
版本
implementation 'org.ehcache:ehcache:3.10.0'
implementation 'com.esotericsoftware:kryo:5.6.0'
代码片段
public class Employee implements Serializable {
String name;
int id;
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
}
public class EmployeeKryoSerializer implements Serializer<Employee> {
private static final Kryo kryo = new Kryo();
public EmployeeKryoSerializer(ClassLoader loader) {
kryo.register(Employee.class);
}
@Override
public ByteBuffer serialize(Employee object) throws SerializerException {
Output output = new Output(new ByteArrayOutputStream());
kryo.writeObject(output, object);
output.close();
return ByteBuffer.wrap(output.getBuffer());
}
@Override
public Employee read(ByteBuffer binary) throws SerializerException {
Input input = new Input(new ByteBufferInputStream(binary));
return kryo.readObject(input, Employee.class);
}
@Override
public boolean equals(Employee object, ByteBuffer binary) throws ClassNotFoundException, SerializerException {
return object.equals(read(binary));
}
}
public class KryoSerializationTest {
public static void main(String[] args) throws IOException {
Employee test = new Employee("TestName", 1);
testNormalKryoDummyObject(test);
testEHCacheDummyObject(test);
}
private static void testNormalKryoDummyObject( Employee test) throws IOException {
Kryo kryo = new Kryo();
kryo.register(Employee.class);
Output output = new Output(new ByteArrayOutputStream());
for (int i = 0; i < 1000; i++) {
kryo.writeObject(output, test);
}
output.close();
FileOutputStream fileOutputStream = new FileOutputStream("kryo_employee.bin");
fileOutputStream.write(output.getBuffer());
fileOutputStream.flush();
fileOutputStream.close();
}
private static void testEHCacheDummyObject(Employee test){
StatisticsService odStatisticsService = new DefaultStatisticsService();
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.using(odStatisticsService)
.build(true);
Cache<String, Employee> odPairCache = cacheManager.createCache("TEST_EH_CACHE",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
String.class,
Employee.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().offheap(100, MemoryUnit.MB).build())
.withValueSerializer(EmployeeKryoSerializer.class)
.build());
for (int i = 0; i < 1000; i++) {
odPairCache.put("XYZ"+i+"-"+"ABC",test);
printEHStatistic("TEST_EH_CACHE", odStatisticsService);
}
}
private static void printEHStatistic(String cacheName, StatisticsService odStatisticsService) {
CacheStatistics cacheStatistics = odStatisticsService.getCacheStatistics(cacheName);
EHCacheStatistic ehCacheStatistic =
EHCacheStatistic.builder()
.cacheName(cacheName)
.cacheMissPercentage(cacheStatistics.getCacheMissPercentage())
.cacheEvictions(cacheStatistics.getCacheEvictions())
.cacheExpirations(cacheStatistics.getCacheExpirations())
.cacheGets(cacheStatistics.getCacheGets())
.cacheMisses(cacheStatistics.getCacheMisses())
.cacheRemovals(cacheStatistics.getCacheRemovals())
.cachePuts(cacheStatistics.getCachePuts())
.cacheHits(cacheStatistics.getCacheHits())
.cacheHitPercentage(cacheStatistics.getCacheHitPercentage())
.tierStats(new ArrayList<>())
.build();
cacheStatistics
.getTierStatistics()
.forEach(
(tierName, tierStats) -> ehCacheStatistic
.getTierStats()
.add(
TierStats.builder()
.tierName(tierName)
.allocatedByteSize(tierStats.getAllocatedByteSize())
.occupiedByteSize(tierStats.getOccupiedByteSize())
.evictions(tierStats.getEvictions())
.expirations(tierStats.getExpirations())
.hits(tierStats.getHits())
.misses(tierStats.getMisses())
.mappings(tierStats.getMappings())
.puts(tierStats.getPuts())
.removals(tierStats.getRemovals())
.build()));
System.out.println(ehCacheStatistic.toString());
}
}
需要知道为什么 EHcache 使用 Kryo Serializer 占用更多空间
我无法说出 Kryo 在做什么,但 Ehcache 中的默认序列化器正在为您提供:
ACED j.i.ObjectStreamConstants.STREAM_MAGIC
0005 j.i.ObjectStreamConstants.STREAM_VERSION
73 j.i.ObjectStreamConstants.TC_OBJECT
72 j.i.ObjectStreamConstants.TC_CLASSDESC
00000000 <class index = 0>
78 j.i.ObjectStreamConstants.TC_ENDBLOCKDATA
70 j.i.ObjectStreamConstants.TC_NULL
00000001 <value of int id>
74 j.i.ObjectStreamConstants.TC_STRING
0008 <8 UTF characters>
546573744E616D65 == TestName
总共 27 个字节。默认的 Ehcache 序列化非常节省空间。我确信只要有足够的配置,您就可以在下面使用 Kryo。不过,对于对 Kyro 更有经验的人来说,这将是一个练习。