سؤال

لدي خادم TCP مكتوب في C # التي تعالج البيانات المرسلة إليها. يعمل حاليا بشكل جيد ما لم يتم إرسال كمية كبيرة من البيانات (أي أكبر من 1GB) إلى ذلك، فهي تنفد من الذاكرة (قمت بتخزين كل شيء في الذاكرة كصفيف من البايتات (مع وسيط لقائمة DTO)). بالنسبة للملفات الكبيرة الآن، أتدفق إلى القرص ثم اجتياز اسم الملف حول نية تدفقه من القرص.

حاليا جميع إجراءاتي مكتوبة لتوقع صفائف البايت التي، في فوات الأوان، قصيرة النظر قليلا. إذا قمت فقط بتحويل ByTearrray إلى مخصص، فهل ستضاعف استخدام الذاكرة؟ أعتقد أن تعيد كتابة التعليمات البرمجية الخاصة بي للعمل على موعد موضة سيسمح لي بإعادة استخدامه عند قراءة دفق من القرص؟

آسف على الأسئلة الغبية، أنا غير متأكد أبدا عندما يستغرق C # نسخة من البيانات أو عندما يستغرق مرجعا.

هل كانت مفيدة؟

المحلول

إذا كنت تمر byte[] الى MemoryStream, ، ثم سيتم نسخ البيانات في البداية (في المنشئ)، ولكن طالما تحرر byte[] يمكن جمع القمامة التي تم جمعها. بطبيعتها لا يوجد "مضاعفة" (خاصة إذا كنت تستطيع ضبط الحجم بشكل صحيح للبدء، والكتابة مباشرة إلى Stream بدلا من byte[]).

أود أن أقول تماما التبديل إلى Stream (لكن فقط استعمال Stream في API - لا شيء معين مخصص؛ لا يحتاج رمز الاستهلاك إلى معرفة أي نوع). الأهم من ذلك، يمكنك اختيار استخدام NetworkStream (للقراءة مباشرة من المقبس) أو FileStream (إذا كنت ترغب في التعامل مع القرص)، أو MemoryStream إذا كنت ترغب في المخزن المؤقت في العملية. ستحتاج أيضا إلى التأكد من أنك تقرأ هذا الحجم من البيانات عبر التعليمات البرمجية المستندة إلى الدفق. كتل ميكرواس (yield return) يمكن أن يكون مفيدا جدا هنا، كما يمكن LINQ Enumerable الأساليب (باستثناء OrderBy, GroupBy, ، إلخ، ما هو المخزن المؤقت).

لا يمر أ byte[] ولا يمر أ Stream يتسبب في نسخ أي شيء، لأنها أنواع مرجعية - الشيء الوحيد الذي تم نسخه هو المرجع (4 أو 8 بايت، اعتمادا على X86 / X64).

نصائح أخرى

موعد موضة مجرد غلاف دفق حول صفيف بايت، لذلك لن تكتسب أي شيء باستخدامه.

ما تحتاجه إلى القيام به (بالنسبة للملفات الكبيرة على الأقل) هو فتح ملف fileestream وتفريغ بياناتك في ذلك. على مستوى أقل، عليك قراءة X بايت من اتصالك ثم اكتب ذلك على الفور إلى دفق الملف الخاص بك. وبهذه الطريقة لن تسحب في أزعج كامل في الذاكرة ولكن فقط عدد قليل من البايتات في وقت واحد.

سواء كان ذلك من السهل أن نفعل ذلك أم لا يعتمد على كيفية ترميز خادم TCP الخاص بك.

نظرا لأن البايت هو نوع القيمة، إذا قمت بتمريرها إلى وظيفة دون الكلمة الأساسية للوظائف التي ستتعامل مع نسخة في كل مرة. إذا قمت بتمريرها مع الكلمة الأساسية REF، فسوف تتخذ مرجعا إلى صفيف البايت الأصلي.

memoryStream هو نوع مرجعي، لذلك لن ينسخ البيانات، لكنك تمر حول إشارة إلى تلك البيانات، لذلك لن يضاعف استخدام ذاكرة الذاكرة عند استخدام ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top