मैं Marshal.AllocHGlobal
के माध्यम से अपने आवेदन में कुछ अप्रबंधित स्मृति आवंटित कर रहा हूं। मैं फिर Marshal.FreeHGlobal
के माध्यम से स्मृति को मुक्त करने से पहले इस स्थान पर बाइट्स का एक सेट कॉपी कर रहा हूं और मेमोरी के परिणामी सेगमेंट को struct
में परिवर्तित कर रहा हूं।Marshal.AllocHGlobal द्वारा आवंटित स्मृति को शून्य कैसे करें?
यहाँ विधि है:
public static T Deserialize<T>(byte[] messageBytes, int start, int length)
where T : struct
{
if (start + length > messageBytes.Length)
throw new ArgumentOutOfRangeException();
int typeSize = Marshal.SizeOf(typeof(T));
int bytesToCopy = Math.Min(typeSize, length);
IntPtr targetBytes = Marshal.AllocHGlobal(typeSize);
Marshal.Copy(messageBytes, start, targetBytes, bytesToCopy);
if (length < typeSize)
{
// Zero out additional bytes at the end of the struct
}
T item = (T)Marshal.PtrToStructure(targetBytes, typeof(T));
Marshal.FreeHGlobal(targetBytes);
return item;
}
यह सबसे अधिक भाग के लिए काम करता है, फिर भी अगर मैं कम बाइट की तुलना में struct
के आकार, आवश्यकता है तो 'यादृच्छिक' मान पिछले क्षेत्रों के लिए (मैं कर रहा हूँ आवंटित कर रहे हैं लक्ष्य संरचना पर LayoutKind.Sequential
का उपयोग कर)। मैं इन लटकते क्षेत्रों को यथासंभव कुशलतापूर्वक शून्य करना चाहता हूं।
संदर्भ के लिए, यह कोड लिनक्स पर सी ++ से भेजे गए उच्च आवृत्ति मल्टीकास्ट संदेशों को deserializing है।
// Give only one byte, which is too few for the struct
var s3 = MessageSerializer.Deserialize<S3>(new[] { (byte)0x21 });
Assert.AreEqual(0x21, s3.Byte);
Assert.AreEqual(0x0000, s3.Int); // hanging field should be zero, but isn't
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
private struct S3
{
public byte Byte;
public int Int;
}
इस परीक्षण चल रहा है बार-बार एक अलग मूल्य के साथ हर बार विफल दूसरा ज़ोर का कारण बनता है:
यहाँ एक असफल परीक्षण का मामला है।
संपादित
अंत में, मैं unsafe
जा रहा है और stackalloc
का उपयोग करने का leppie's suggestion इस्तेमाल किया। इसने एक बाइट सरणी आवंटित की जिसे आवश्यकतानुसार शून्य किया गया था, और संदेश आकार के आधार पर 50% से 100% के बीच थ्रूपुट में सुधार हुआ (बड़े संदेशों में अधिक लाभ देखा गया)।
public static T Deserialize<T>(byte[] messageBytes, int startIndex, int length)
where T : struct
{
if (length <= 0)
throw new ArgumentOutOfRangeException("length", length, "Must be greater than zero.");
if (startIndex < 0)
throw new ArgumentOutOfRangeException("startIndex", startIndex, "Must be greater than or equal to zero.");
if (startIndex + length > messageBytes.Length)
throw new ArgumentOutOfRangeException("length", length, "startIndex + length must be <= messageBytes.Length");
int typeSize = Marshal.SizeOf(typeof(T));
unsafe
{
byte* basePtr = stackalloc byte[typeSize];
byte* b = basePtr;
int end = startIndex + Math.Min(length, typeSize);
for (int srcPos = startIndex; srcPos < end; srcPos++)
*b++ = messageBytes[srcPos];
return (T)Marshal.PtrToStructure(new IntPtr(basePtr), typeof(T));
}
}
दुर्भाग्य से यह अभी भी Marshal.PtrToStructure
के लिए एक कॉल की आवश्यकता है लक्ष्य प्रकार में बाइट्स कन्वर्ट करने के लिए:
अंतिम विधि जैसी समाप्त हो गया।
@leppie - उपयोगी जानकारी के लिए धन्यवाद। मैं 'स्टैकलोक' भी देखूंगा। मुझे अलग-अलग संदेश आकारों को पूरा करना होगा क्योंकि दोनों टीमें कभी-कभी सिंक्रनाइज़ रिलीज़ से बचने के लिए प्रबंधन कर सकती हैं अगर हम अंत में फ़ील्ड्स जोड़ते हैं जो दूसरे छोर को अनदेखा करते हैं। इसी प्रकार, यदि आपको मूल्यों की आवश्यकता नहीं है, तो आप उन्हें उम्मीद कर सकते हैं और इसके बजाय शून्य प्राप्त कर सकते हैं, जो मामला मैं यहां हासिल करने की कोशिश कर रहा हूं। –
@leppie, मैं इस दृष्टिकोण की ओर झुका रहा हूँ। क्या आप कुछ और विस्तार में जा सकते हैं क्योंकि 'stackalloc' का उपयोग करके _why_ सुरक्षित और तेज़ है? एक बार मेरे पास 'बाइट *' हो, तो इसमें प्रतिलिपि बनाने का सबसे अच्छा तरीका क्या होगा? –
मैंने एक संस्करण एक साथ रखा है जो स्टैक पर एक सरणी को पॉप्युलेट करने के लिए 'stackalloc' के साथ काम करता है। मुझे नहीं लगता कि 'मार्शल.प्रेटोस्ट्रक्चर' को कॉल के आसपास जाना संभव है, है ना? –