zoukankan      html  css  js  c++  java
  • FluorineFx的AMFWriter实现的也太粗心了...

        前两天打算给组件做个AMF3适配器用于组件和Flash进行通讯交互,经了解后发现FluorineFx在.net下对AMF3支持比较完善的一个项目,于就下载下来做一下集成.出于好奇于是看了一下相关代码,由于只需要用到序列化问题所以只关注了一下AMFWriter;从实现代码来看AMFWriter基本没有考虑高并发下的GC压力,数据写入过程基本都是通过new byte[]复制的方式.为了进行步了解于是对FluorineFx序列化对象做了个内存分析.

        出来的结果让我摸不着头脑.

    损耗排在前面的竟然一些意想不到的对象...于是详细跟踪进行发现这两个对象的开销都来源于AMFWriter.GetMember方法;细看这个方法我当场晕倒:

    internal object GetMember(object instance, ClassMember member)
            {
                if (instance is ASObject)
                {
                    ASObject aso = instance as ASObject;
                    if (aso.ContainsKey(member.Name))
                        return aso[member.Name];
                }
                Type type = instance.GetType();
                if (member.MemberType == MemberTypes.Property)
                {
                    
                    PropertyInfo property= type.GetProperty(member.Name, member.BindingFlags);
                    return property.GetValue(instance, null);
                }
                if (member.MemberType == MemberTypes.Field)
                {
                    FieldInfo field = type.GetField(member.Name, member.BindingFlags);
                    return field.GetValue(instance);
                }
                string msg = __Res.GetString(__Res.Reflection_MemberNotFound, string.Format("{0}.{1}", type.FullName, member.Name));
                throw new FluorineException(msg);
            }

        获取成员值的方法竟然每次都会GetProperty或GetField,所以在测试内存结果为什么PropertyInfo[]占第一位置的原因.其实PropertyInfo和FieldInfo都是线程安全根本没有必要做.于是做了简单的调整

    internal object GetMember(object instance, ClassMember member)
            {
                if (instance is ASObject)
                {
                    ASObject aso = instance as ASObject;
                    if (aso.ContainsKey(member.Name))
                        return aso[member.Name];
                }
                Type type = instance.GetType();
                if (member.MemberType == MemberTypes.Property)
                {
                    if(member.Property ==null)
                        member.Property= type.GetProperty(member.Name, member.BindingFlags);
                    return member.Property.GetValue(instance, null);
                }
                if (member.MemberType == MemberTypes.Field)
                {
                    if(member.Field ==null)
                        member.Field = type.GetField(member.Name, member.BindingFlags);
                    return member.Field.GetValue(instance);
                }
                string msg = __Res.GetString(__Res.Reflection_MemberNotFound, string.Format("{0}.{1}", type.FullName, member.Name));
                throw new FluorineException(msg);
            }

        同样在查看代码中发现WriteAMF3UTF也很有问题,于是也调整了一下

    static void _WriteAMF3UTF(string value, AMFWriter writer)
            {
                lock (_LockWriterString)
                {
                    if (value == string.Empty)
                    {
                        writer.WriteAMF3IntegerData(1);
                    }
                    else
                    {
                        if (!writer._stringReferences.ContainsKey(value))
                        {
                            writer._stringReferences.Add(value, writer._stringReferences.Count);
    
                            int byteCount = Encoding.UTF8.GetBytes(value, 0, value.Length, encodingdata, 0);
                            int handle = byteCount;
                            handle = handle << 1;
                            handle = handle | 1;
                            writer.WriteAMF3IntegerData(handle);
    
                            if (byteCount > 0)
                                writer.Write(encodingdata,0,byteCount);
                        }
                        else
                        {
                            int handle = (int)writer._stringReferences[value];
                            handle = handle << 1;
                            writer.WriteAMF3IntegerData(handle);
                        }
                    }
                }
            }
            /// <summary>
            /// Writes a UTF-8 string to the current position in the AMF stream.
            /// </summary>
            /// <param name="value">The UTF-8 string.</param>
            /// <remarks>Standard or long string header is not written.</remarks>
    		public void WriteAMF3UTF(string value)
    		{
                _WriteAMF3UTF(value, this);
                //if( value == string.Empty )
                //{
                //    WriteAMF3IntegerData(1);
                //}
                //else
                //{
                //    if (!_stringReferences.ContainsKey(value))
                //    {
                //        _stringReferences.Add(value, _stringReferences.Count);
                //        UTF8Encoding utf8Encoding = new UTF8Encoding();
                //        int byteCount = utf8Encoding.GetByteCount(value);
                //        int handle = byteCount;
                //        handle = handle << 1;
                //        handle = handle | 1;
                //        WriteAMF3IntegerData(handle);
                //        byte[] buffer = utf8Encoding.GetBytes(value);
                //        if (buffer.Length > 0)
                //            Write(buffer);
                //    }
                //    else
                //    {
                //        int handle = (int)_stringReferences[value];
                //        handle = handle << 1;
                //        WriteAMF3IntegerData(handle);
                //    }
                //}
    		}

        从整个AMFWriter的实现代码来说,发现作者内存开销方面没有任何意识,那也难怪MS在推出.NET的时候就告诉我们不需要管内存,我们会把它搞定...

    调整前后序列化10000个order的效率对比.

    总的来说AMFWriter的每个写入数据方法都有可优化的余地,看FluorineFx持官网似乎有商业支持,但代码修改日期已经是很久以前,竟然没意识到这一点感觉有点惊讶.

    访问Beetlex的Github
  • 相关阅读:
    Linux中配置别名
    Linux下的IO监控与分析
    RHEL6 Systemtap 安装笔记
    记一次多事件绑定中自己给自己设置的坑——click,dblclick,mousedown,mousemove,mouseup
    springboot打jar获取不到static静态资源文件问题
    关于springboot默认日志框架Slf4j+logback,自定义Appender问题
    spring 时间格式问题
    springboot 部署到tomcat,获取根路径问题。空格变为%20
    前后端分离 vue+springboot 跨域 session+cookie失效问题
    springboot 部署到tomcat中,项目总是重新部署
  • 原文地址:https://www.cnblogs.com/smark/p/2531089.html
Copyright © 2011-2022 走看看