BigMemroy系列文章--11. BigMemory中的SizeOf问题

转载请注明出处哈:http://carlosfu.iteye.com/blog/2237511

 感谢博主:hot66hot.iteye.com/


 一:BigMemory如何使用DirectMemory内存

 

   以下是bigMemory启动时打印的DirectMemory分区概述:

Maximum Size (specified) : 32MB
Minimum Chunk Size : 8MB
Maximum Chunk Size : 32MB
Concurrency : 16
Initial Segment Table Size : 64 slots
Segment Data Page Size : 64KB

 

根据日志,可以猜测出BigMemory预先将数据空间划分为一系列Chunk,目的为了防止内存碎片化,与Memcache内存分配策略很像.

借用下memcache 的chunk空间分配过程图,可以更好的理解.

 

有个问题:bigMemory必须知道存储的对象所占用的空间,才能选择合适的chunk存放对象.

 

二:BigMemory计算对象所占空间

 

EHCache计算一个实例占用的内存大小。

BigMemroy系列文章--11. BigMemory中的SizeOf问题_第1张图片
基本思路:遍历实例数上的所有节点,对每个节点计算其占用的内存大小。

使用反射的方式计算一个实例占用的内存大小。

反射计算一个实例(instance)占用内存大小(size)过程如下: 
  a. 如果instance为null,size为0,直接返回。 
  b. 如果instance是数组类型,size为数组头部大小+每个数组元素占用大小* 数组长度+填充到对象对齐最小单位。 
  c. 如果instance是普通实例,size初始值为对象头部大小,然后找到对象对应类的所有继承类,从最顶层类开始遍历所有类,对每个类,纪录长整型和双精度型、整型和浮点型、短整型和字符型、布尔型和字节型以及引用类型的非静态字段的个数。在所有类计算完成后,按类对齐规则对齐等

参考资料:http://www.importnew.com/1305.html

 

EHCache中的SizeOf类中采用deepSize计算,它的步骤是:使用ObjectGraphWalker遍历一个实例的所有对象引用,在遍历中通过使用传入的SizeOfFilter过滤掉那些不需要的字段,然后调用传入的Visitor对每个需要计算的实例做计算。 
ObjectGraphWalker的实现算法使用了Stack,也可以使用Queue,这个影响遍历的顺序,深度优先还是广度优先的区别。它抽象了SizeOfFilter接口,可以用于过滤掉一些不想用于计算内存大小的字段,如Element中的key字段。SizeOfFilter提供了对类和字段的过滤:

public interface SizeOfFilter { 
// Returns the fields to walk and measure for a type 
Collection<Field> filterFields(Class<?> clazz, Collection<Field> fields); 
// Checks whether the type needs to be filtered 
boolean filterClass(Class<?> klazz); 
}

 

   SizeOfFilter的实现类可以用于过滤过滤掉@IgnoreSizeOf注解的字段和类,以及通过net.sf.ehcache.sizeof.filter系统变量定义的文件,读取其中的每一行为包名或字段名作为过滤条件。最后,为了性能考虑,它对一些计算结果做了缓存。 

结论: Bigmemory的主要开销:序列化+sizeOf计算

 

三:sizeOf引擎优化与测试:

 

1:对sizeOf引擎友好的对象:尽量使用不深/不广的对象:深(继承树) 广( bigPojo,ArrayList,HashMap等)

2:这边使用了大量的ArrayList和HashMap 等对象.日志给出bigMemory警告如下,

2014-04-09 17:30:54,376 [DubboServerHandler-10.10.34.12:20880-thread-248] WARN net.sf.ehcache.pool.impl.DefaultSizeOfEngine (DefaultSizeOfEngine.java:194) - The configured limit of 2,000 object references was reached while attempting to calculate the size of the object graph. This can be avoided by adding stop points with @IgnoreSizeOf annotations. Since the CacheManger or Cache <sizeOfPolicy> elements maxDepthExceededBehavior is set to "abort", the sizing operation has stopped and the reported cache size is not accurate. If performance degradation is NOT an issue at the configured limit, raise the limit value using the CacheManager or Cache <sizeOfPolicy> elements maxDepth attribute. For more information, see the Ehcache configuration documentation.

 

为了减少sizeOf计算开销,加入配置:计算超过2000次后终止,但这样会造成chunk分配混乱.

 

<sizeOfPolicy maxDepth="2000" maxDepthExceededBehavior="abort"/>

 

3:采用protostuff预前序列化的方式,bigMemory只存protostuff序列化后的byte数组

如下图:


BigMemroy系列文章--11. BigMemory中的SizeOf问题_第2张图片
 

 

 4:测试用例: 测试采用单线程压测100W次,directMemory空间为100MB.,对象实际值完全相同.


BigMemroy系列文章--11. BigMemory中的SizeOf问题_第3张图片
 


四、结论:
 

1. 采用预序列化(protostuff)之后set性能有3倍的提高,get性能提高50%以上。

2. 随着对象复杂度增加,相同空间预序列化(protostuff)方式占用空间更少,如HashMap的测试用例.

3. 但是如果对象是简单的pojo,则原生的bigMemory占用空间更有优势.

4. 根据自身系统的对象类型做处理.

你可能感兴趣的:(序列化,sizeof,JMM,protostuff,BigMemory)