顯示具有 Serialization 標籤的文章。 顯示所有文章
顯示具有 Serialization 標籤的文章。 顯示所有文章

2017年7月22日 星期六

[.NET] 流(Stream)的理解心得


Wiki說得好:
「流」是一連串從I/O設備讀寫的字符(Byte)

流(Stream)是.NET中非常基礎的型態,存取方式是很單純的位元組依序寫入/讀出(Byte by Byte Writing/Reading),會有一個內藏Counter紀錄住目前存取位置(Position,有點類似座標),存取時都是從目前位置開始存取.

若將整個讀取完畢的Stream攤平開來,也是可以想像成時域信號圖,橫軸是位置,只是要確定好座標原點(Origin)在何處

跟位元組陣列有著類似的概念,只是位元組陣列可以隨機存取:給定INDEX存取,座標原點就是第一個元素,只需一個存取動作:給定INDEX後返回該位置的資料;若要做類似隨機存取操作,Stream必須先透過Seek改變目前位置,才能開始存取,因此需要兩個存取動作:改變目前位置、存取資料

Stream存的個別元素是位元組,也就是0-255之間的一個數值,可以說是資訊系統內超級底層的資料型態之一,也就是說Stream是一種極為基礎的資料儲存結構;任何的高階資料型態(物件、字串)都能轉換成位元組形式去表達(某種映射):

  • 物件-位元組轉換(物件與位元組之間的映射)
    • 序列化與反序列化(Serialization/Deserialization)
    • 而反序列化/序列化則是互為反函式(Inverse)

  • 字元-位元組轉換(字元與位元組之間的映射)
    • 按字碼表Encoding/Decoding
    • 線性映射?
Stream的資料表達方式容易直接轉化為現實上的物理資料傳輸,舉凡磁碟資料寫入(File)、網路資料傳輸、通訊埠資料傳輸,都是出口Stream(Out-Stream)內按位元組取出,轉化成位元(1/0)脈衝信號後在物理層一點一滴傳達;接著在目標系統物理層中收集這些脈衝信號還原成位元組,按位元組一個一個塞進目標系統的入口Stream(In-Stream)中

後續應用就視情況看是要透過反序列化還是Decoding,轉換成更高階的資料表達型態

.NET的類別規劃上,可以在相關的硬體抽象物件找到Stream的身影,好比說以下衍生自Stream的型別:
既然都是Stream,肯定是有共同性質的:)後續研究學習

參考:這系列對於Stream介紹蠻不錯

2017年7月16日 星期日

[.NET] 記憶體洩漏(Memory Leak)可能原因 - XML Serializer


承接此篇

.NET最爽的就是背後有GC(Garbage Collection)罩著,想配置物件就配置物件(NEW),用完拍拍屁股就走了,等下就會有服務生來收碗盤了,多爽!

可是如果你點到的菜是XML Serializer,可能就沒辦法那麼幸運了,GC是不收這道菜的,亂點到最後...整個餐廳桌上都會是你之前吃剩的XML Serializer

GC無法自動回收XML Serializer,(原因Dynamically Generated Assemblies段落),過於任性大量配置Serializer的話,記憶體可是會爆的

既然如此只能讓自己勤勞點,MSDN推薦的作法是,快取(Cache)住使用過的XML Serializer,每次欲利用XML Serializer時,統一向管理函式索取,若快取庫內沒有,則重新配置一個,若有,則取出既有的參考傳回,如此一來再利用時便不用重新配置,也就避免了潛在的記憶體洩漏問題了

參考以下程式碼:

  • 函式原型:
    • 引數 - 要序列化的物件型別(若物件是衍生自某基底型別,則透過陣列傳入具體衍生型別)
    • 傳回值 - XML Serializer實例
    • 視野(Scope): public static,視為工具函式(Utility)



 
 class utilities
    {
        /// <summary>
        /// Used to store key-serializer
        /// </summary>
        /// <returns></returns>
        private static Hashtable __dictionary = new Hashtable(); 
        /// <summary>
        /// Generate key according to contents of type list
        /// </summary>
        /// <param name="typeList"></param>
        /// <returns></returns>
        protected static int generateKey(List<Type> typeList)
        {
            //hash code summarize
           return typeList.Sum(__type => __type.GetHashCode());
        }
        /// <summary>
        /// Always fetch serializer from this function
        /// (Never allocate by yourself)
        /// </summary>
        /// <param name="mainType"></param>
        /// <param name="extraTypes"></param>
        /// <returns></returns>
        public static XmlSerializer getSerializer(Type mainType,Type[] extraTypes){
            
            //merge the list
            List<Type> __typeList = new List<Type>();

            __typeList.Add(mainType);
            __typeList.AddRange(extraTypes);

            var key = generateKey(__typeList);

            if (__dictionary.ContainsKey(key))
            {
                // this kind of serializer had been cached/used before , 
                // get the cached serializer
                return (XmlSerializer)__dictionary[key];
                }
            else
            {
                // never been used , need to create a new one and push into cache
                XmlSerializer __serializer = new XmlSerializer(mainType,extraTypes);
                __dictionary.Add(key,__serializer);
                return __serializer;
             }
        }//getserializer
    }//utilities

參考程式碼:https://github.com/smandyscom/cached_xmlSerializer

2014年11月15日 星期六

[.NET] TCP使用筆記1--物件序列化/反序列化傳送接收

將物件序列化後傳送串流 ------> 收到串流後反序列化還原物件

Import System.Runtime.Serialization.Formatters.Binary
<Serializable()>
Public Class MySerializableClass   ' Define a Class which is able to be serialized '
    Property s As String = "abcdedfg"
    Property i As Integer = 50
    Property f As Double = 3.14159256
End Class

Dim clientSend As TcpClient = New TcpClient()        'used to send stream'
Dim clientReceive As TcpClient = new TcpClient()     'used to receive stream'

Sub serializeAndSend()
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   bf.Serialize(clientSend.GetStream(), New MySerializableClass())   ' Serialize object and write into net-stream '
End Sub

Function receiveAndDeserialize() As Object
   Dim bf As BinaryFormatter = New BinaryFormatter()             
   return bf.Deserialize(clientReceived.GetStream())   ' stream received and deserialize to object'
End Function

其中BinaryFormatter可用在任何串流的序列化/反序列化(檔案串流、網路串流、記憶體串流…等等) ,
可延伸此法將物件資料存入/讀出磁碟,比方機台參數設定...等等,或是做大型物件的記憶體內複製(應用記憶體串流)。