Kryo 序列化器比 EHCache 中的默认序列化器消耗更多空间

问题描述 投票:0回答:1

我尝试使用 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 占用更多空间

java serialization ehcache kryo ehcache-3
1个回答
0
投票

我无法说出 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 更有经验的人来说,这将是一个练习。

© www.soinside.com 2019 - 2024. All rights reserved.