گفتگو هایی در باب سی شارپ

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
تو Task Manager می توانید اولویت اجرای هر پروسه عادی ای رو با راست کلیک تغییر بدید، اگه پایین بیاریدش اجرای سریع و یکنواخت اش براتون مهم نیست، ولی اگه زیادی بالا ببریدش سیستم اونقدر مشغول اش میشه که عملا مجال کنترل سایر اجزاء ویندوز رو از دست میده و رابط کاربری سیستم میره تو کما. ویندوز نیست که هنگ کرده، برنامه تونه که معطلش می کنه، خود برنامه تون در کما نمیره، در حال اجرا است ولی مجالی به واسط کاربری سیستم داده نمیشه. این خودش خیلی بد ئه، کاربر ها از همچین برنامه ای خوششون نمیاد. حتی نرم افزار های خیلی سنگین محاسباتی هم همچین روالی ندارند که کل توان پردازنده رو صرف خودشون کنند.

سلام
ممنون بابت توضیح پست قبلی
استاد علی ، اینو توی صفحه ی 18 گفته بودین
وقتی در task manager بصورت دستی، قسمت priority پروسه مو realtime میکنم ، 100 در 100 از یک هسته رو فقط استفاده میکنه ولی وقتی با دستور
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.RealTime;
این کار رو میکنم ، 100 در 100 رو اشغال میکنه اما هر بار در هسته های مختف . یعنی هر لحظه ، پروسه ام سوئیچ میکنه روی هسته های مختلف و اون هسته ی مورد نظر رو 100 در 100 اشغال میکنه

فرق این دو چیه که یکی فقط روی یه هسته تمرکز میکنه و با کدنویسی ، روال عادی اش یعنی سوئیچ کردن روی هسته های مختلف ، برقراره؟
میشه با کدنویسی کاری کرد که پروسه مون فقط روی یه هسته قفل کنه و سوئیچ نکنه؟


معنی اش اینه که اون کلاس Button یک پنجره استاندارد ویندوز از کلاس دکمه ساخته که جزو منابع سیستم ئه و Handle پنجره و فونت و ... داره. این منابع مستقیما با API ویندوز در ارتباط اند، فقط یک متغیر حافظه نیستند که تحت کنترل GC باشند و خود شیء مسئول آزاد کردن به موقع اونها است. مثل همون Form ها که Handle استاندارد پنجره ها رو دارند ولی در عین حال کلاس Form ئه NET. یک ساختار مخصوص خودش رو داره.
وقتی این شیء Button قراره Dispose بشه باید تمامی این منابع سیستم مثل اون پنجره ایجاد شده پاک بشه وگرنه یکی از ظرفیت منابع آزاد سیستم کم میشه. Dispose هم اون دکمه استاندارد رو با Handle اش و سایر موارد دیگه که داخل شیء موقع ایجاد شدن دکمه ایجاد شده بود نابود می کنه. شیء از کلاس Button باقی میمونه و پاک نمیشه چون خودش یک شیء NET. ئه و مربوط به این منابع سیستمی نیست.

این رو هم در صفحه ی 18 گفته بودین
هر چند متوجه شدم ولی بنیادین متوجه نشدم :)
کلا میشه بنیادین توضیح بدین که منظورتون از منابع سیستم چیه؟
من این درک رو از این مطلب تون کردم . ببینین درسته؟ :

اشیایی مثل کنترل ها (و حتی کلاس های کار با فایل ها و کلا هر چیزی که مایکروسافت برای اون کلاس ، اینترفیس IDisposable رو پیاده سازی کرد) ، با api ویندوز باید برای ساخته شدن در ارتباط باشن (هر چند قبلا گفته بودین که کلاس های های دات نت مثل کنترل های دات نت ، برخلاف برنامه های Unmanaged ، به کدهای api ویندوز ربطی ندارن . این رو چجوری توجیه میکنین؟) . متد dispose که اجرا بشه ، این ارتباط رو قطع میکنه و این قطع شدن ارتباط ، باعث میشه شی ای دیگه نمایش داده نشه اما کماکان شی (در حافظه ی هیپ . الان منو نزنین :green:) سرجای خودش باقی میمونه
 

the_king

مدیرکل انجمن
سلام
ممنون بابت توضیح پست قبلی
استاد علی ، اینو توی صفحه ی 18 گفته بودین
وقتی در task manager بصورت دستی، قسمت priority پروسه مو realtime میکنم ، 100 در 100 از یک هسته رو فقط استفاده میکنه ولی وقتی با دستور
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.RealTime;
این کار رو میکنم ، 100 در 100 رو اشغال میکنه اما هر بار در هسته های مختف . یعنی هر لحظه ، پروسه ام سوئیچ میکنه روی هسته های مختلف و اون هسته ی مورد نظر رو 100 در 100 اشغال میکنه

فرق این دو چیه که یکی فقط روی یه هسته تمرکز میکنه و با کدنویسی ، روال عادی اش یعنی سوئیچ کردن روی هسته های مختلف ، برقراره؟
میشه با کدنویسی کاری کرد که پروسه مون فقط روی یه هسته قفل کنه و سوئیچ نکنه؟
هر دو شون یک کار رو انجام میدن، اما مساله مهلت برای سوئیچ کردنه نه سوئیچ نکردن. وقتی شما ما بین اجرای یک روتین سطح ارجحیت رو از بیرون پروسه عوض می کنین سیستم دیگه فرصتی برای سوئیچ کردنش پیدا نمی کنه. در نظر بگیرید که در حالت کلی کد شما در ماشین مجازی اجرا میشه و کد دخالتی در انتخاب هسته حقیقی پردازنده نداره. ارتباط مستقیم و کنترل روی پردازنده مربوطه به هسته سیستم عامل ئه، برنامه شما نمیتونه دخالتی روی بخش های تحت کنترل هسته سیستم عامل داشته باشه. پروسه برنامه شما خودش احتیاج به یک عالمه سرویس داره که سیستم عامل و اجزاء دیگه بهش میدن، مود RealTime اصلا مناسب پروسه های این چنینی نیست. وقتی پروسه وقت کامل یک هسته رو بصورت کامل بگیره سایر پروسه های روی اون هسته اجراشون مختل میشه و از اونجایی که نه شما روی انتخاب اون پروسه ها نقشی دارید و نه از عواقب تاخیر در اجراشون مطلع هستید نمی توانید مانع توقف سرویس های مورد نیاز خود پروسه هم بشید.
این رو هم در صفحه ی 18 گفته بودین
هر چند متوجه شدم ولی بنیادین متوجه نشدم :)
کلا میشه بنیادین توضیح بدین که منظورتون از منابع سیستم چیه؟
من این درک رو از این مطلب تون کردم . ببینین درسته؟ :

هر چیزی که سیستم عامل در اختیار برنامه شما قرار میده منابع سیستم ئه، حافظه RAM و File System و WMI و Registry و Font و Brush و Theme فرم ها و صفحه کلید و ماوس و ساعت و پردازنده و کمک پردازنده و ... همه منابعی ئه که مالک شون سیستم عامله و برنامه شما فقط اونها رو موقتی قرض میگیره.

اشیایی مثل کنترل ها (و حتی کلاس های کار با فایل ها و کلا هر چیزی که مایکروسافت برای اون کلاس ، اینترفیس IDisposable رو پیاده سازی کرد) ، با api ویندوز باید برای ساخته شدن در ارتباط باشن (هر چند قبلا گفته بودین که کلاس های های دات نت مثل کنترل های دات نت ، برخلاف برنامه های Unmanaged ، به کدهای api ویندوز ربطی ندارن . این رو چجوری توجیه میکنین؟)
آخه ربطی نداره که. یه عالمه زبان برنامه نویسی و کامپایلر هست که باهاشون در ویندوز برنامه نوشته میشه و همه شون فرضا دکمه های استاندارد ویندوز رو به طریقی روی فرم نشون میدن. هر کدوم شون هم مفهوم متفاوتی برای کلاس دارند، شایدم اصلا شیء گرایی به اون صورت نداشته باشن و اصلا کلاس تعریف کردن براشون معنی نداشته باشه، کلاس های خود زبان رو که نمیتونید مستقیما ربط بدید به API ویندوز. در NET . برای دسترسی به هر روتینی که به نوعی با API در ارتباطه یک کلاسی، ماژولی چیزی هست که یک پوسته بدور اون ارتباط ایجاد کرده. فرضا همون System.Diagnostics.Process یا Button یا Form و ...
دلیلی نداره که چون یک روتینی با دسترسی به API یک پنجره می سازه، خودش ربطی به API داشته باشه. اینها یک پوسته بدور اون هستند. شما که نمی توانید در API یک پنجره از کلاس Button بسازید و بعد نابود و منابعش رو آزاد کنید ولی همچنان دکمه نابود شده Handle و Text داشته باشه. همچین چیزی توی ویندوز محاله. وقتی پنجره نابود شد، دیگه پنجره ای و Handle معتبری برایش وجود نداره، نه Handle داره و نه Text ای. اما در #C شما دکمه میسازید و نابودش می کنید ولی همچنان Text دارید. این Text یک جزئی از کلاس NET. ئه، هیچ ربطی به API ویندوز و GetWindowText و پنجره و Handle و دکمه های استاندارد ویندوز نداره :
کد:
            var b = new Button() { Name = "My Button" };
            b.Dispose();
            MessageBox.Show(b.Name);

. متد dispose که اجرا بشه ، این ارتباط رو قطع میکنه و این قطع شدن ارتباط ، باعث میشه شی ای دیگه نمایش داده نشه اما کماکان شی (در حافظه ی هیپ . الان منو نزنین :green:) سرجای خودش باقی میمونه
اون چیزی که سر جاش میمونه شیء از کلاس #C ئه. این کلاس و شیء مفهومی ئه که مربوط به زبان #C و ساختار خودشه. ربطی به API که نداره. #C وقتی میخواد یک شیء از کلاس Class1 بسازه یا یک شیء از نوع object بسازه که نمیاد به API ویندوز درخواست ساختن شیء بده، در هر زبانی این شیء و کلاس تعاریف و پیاده سازی خودشو داره، به API کاری نداره. شما یک کلاس دارید که داخلش یک یا چند منبع از سیستم دریافت میشه، حالا اصلا اسم کلاس Button باشه یا Hasan باشه مهم نیست، مهم اینه که از سیستم عامل منبع دریافت کردید. این منابع هم قرضی ئه، باید پس اش بدید. باید یعنی اصولی ئه که پس بدید. شاید کدتون رو اصولی ننویسید و اصلا پس هم ندید، اما اصولی اش اینه که وقتی کارتون باهاشون تموم شد آزاد شون کنید. Dispose از این جهت جای مناسبیه برای پس دادن این منابع. همین. وگرنه نمایش دکمه و فرم و ... که همه توابع و سرویس های API هستند، شما می توانید اصلا مستقیما با توابع رسم تم ویندوز کار کنید و بدون ساختن دکمه رسم اش کنید، چیزی که شما عملا Dispose می کنید پنجره ای ئه که بابت ساختن دکمه از سیستم عامل گرفته بودید، نه Button. اون Button رو ویندوز نه میشناسه چیه و نه میتونه باهاش کاری داشته باشه. سیستم عامل که به زبان #C آشنایی نداره. رسم اون دکمه هم فقط یک روتین ئه، به سیستم عامل پیام میدید که رخداد WM_PAINT رو انجام بده و دکمه رسم میشه، خیلی ساده. ویندوز چک می کنه classname (با کلاس در #C اشتباه گرفته نشه) پنجره ای که ساخته اید چیه و اگه بشناسه بر اساس کلاس های آماده اش رسم مناسبش رو انجام میده. کاری نداره و نمیتونه بفهمه که این کلاس #C ای که همچین پنجره ای رو ساخته اسمش چیه و کاربردش چیه. سیستم عامل فقط پنجره های استاندارد ویندوز رو با روتین های پیشفرض خودش مدیریت می کنه. ممکنه در یک کلاس چند تا از این پنجره های ویندوز درخواست کنید و بسازید، ویندوز که به این قضیه کاری نداره که حالا بخواد کلاس ایجاد کننده اش در #C رو نابود بکنه یا نکنه.
 

SU-57

Active Member
سلام

سجاد جان این کد رو ببین

کد:
string mah = "Ordibehesht";


            switch (mah)
            {
                case "Farvardin":
                    MessageBox.Show("1");
                    break;

                case "Ordibehesht":
                    goto myLabel;
                 
                case "Khordad":
                    MessageBox.Show("3");
                    break;

            }

        myLabel:
            MessageBox.Show("2");

خوب وقتی به case دوم می رسه می بینه درسته و میره myLabel رو اجرا می کنه. اما کد زیر رو هم ببین که من مقدار case دوم رو اشتباه میدم باز هم myLabel رو اجرا می کنه یعنی من می خوام فقط وقتی case من درست بود myLabel رو اجرا کنه و اگه درست نبود اصلا اجرا نکنه (آخرای قسمت 12)

کد:
string mah = "Ordibehesht";


            switch (mah)
            {
                case "Farvardin":
                    MessageBox.Show("1");
                    break;

                case "Tir":
                    goto myLabel;
                 
                case "Khordad":
                    MessageBox.Show("3");
                    break;

            }

        myLabel:
            MessageBox.Show("2");
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام

سجاد جان این کد رو ببین

کد:
string mah = "Ordibehesht";


            switch (mah)
            {
                case "Farvardin":
                    MessageBox.Show("1");
                    break;

                case "Ordibehesht":
                    goto myLabel;
                
                case "Khordad":
                    MessageBox.Show("3");
                    break;

            }

        myLabel:
            MessageBox.Show("2");

خوب وقتی به case دوم می رسه می بینه درسته و میره myLabel رو اجرا می کنه. اما کد زیر رو هم ببین که من مقدار case دوم رو اشتباه میدم باز هم myLabel رو اجرا می کنه یعنی من می خوام فقط وقتی case من درست بود myLabel رو اجرا کنه و اگه درست نبود اصلا اجرا نکنه (آخرای قسمت 12)

کد:
string mah = "Ordibehesht";


            switch (mah)
            {
                case "Farvardin":
                    MessageBox.Show("1");
                    break;

                case "Tir":
                    goto myLabel;
                
                case "Khordad":
                    MessageBox.Show("3");
                    break;

            }

        myLabel:
            MessageBox.Show("2");

سلام آقا رامین
به switch ربط نداره
شما کلا switch رو هم که حذف کنید ، میبینید که بازم myLabel اجرا میشه
با break point میتونین روند اجرای کد رو ببینین
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
استاد علی ، من کد :

کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Mokhtar Nameh\mokhtar name 2.divx"))
            {
                string a = file.ReadToEnd();
            }

رو که اجرا میکنم (حجم فایلم حدودا 250 مگ هست) ، بعد از اتمام بلاک ، هیچ چی از منابع و رم آزاد نمیشه و 1 گیگ از رم رو اشغال میکنه با اونکه توی دستور using نوشته و متد dispose رو فراخونی میکنه
چرا؟
فقط بعد از بلاک using ، متد GC.Collect() رو فراخونی میکنم ، اشغال رم به حدود 500 مگ کاهش پیدا میکنه ولی به حالت اولیه اش (قبل از خوندن فایل) که 7 مگ رو اشغال میکرد ، نمیرسه
چی کار باید کنم تا به حالت اولش برگرده؟
بعد اینکه فایل ای که قراره بخونه ، حدود 250 مگ حجمش هست اما چرا موقع خوندن فایل ، حدود 1 گیگ (یعنی 4 برابر بیشتر از حجم خود فایل) در رم رو اشغال میکنه؟!
توی لوا هم همین جوری بود . هم قضیه ی چندین برابر اشغال کردن حجم و هم قضیه ی گربگ کالکتور منتها گربگ الکتور در لوا وقتی فراخونی میشد ، تقریبا همه چیزرو پاک میکرد و حجم رم اشغالی برنامه ، به حالت اولیه ی خودش برمیگشت
-----------------------------
بعد اینکه انجمن چرا چند هفته ای هست هی قاتی میکنه؟
ممنون
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
جوابش رو پیدا کردم
باید متغییر رشته رو قبل از فراخونی متد GC.Collect() ، باید null کنم تا از رم پاک شه :


کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
                a = null;
            }
           
            GC.Collect();

ولی یه سئوال .
مگه وقتی کنترل برنامه به اتمام بلاک در using در بالا برسه ، اتوماتیک متغییر a که تعریف شده ، اشاره گرش از دست نمیره؟ اگه این طوری باشه (از دست بره) ، دیگه نیازی به null کردن متغییر نیست و اگه از دست نره ، پس من قبلا در یه مقاله ای خونده بودم که وقتی متغییرها به اتمام بلاک برسن ، پاک میشن (که لینک اون مقاله رو هم بهتون دادم)
الان متغییر file در بالا ، حجم خاصی از رم رو اشغال نمیکنه . همش واسه اون متغییر a هست . متوجه ی کاربرد متد dispose در StreamReader نشدم . منابع سیستمش چیزی از رم اشغال نکرد که !
حالا سئوال مهم اینه که وقتی GC.Collect(); رو فراخونی نکنم ، حدود 800 مگ از رم اشغال میشه (این یه فایل دیگه با حجم 200 مگ هست) ولی اگه بدون null کردن متغییر a متد GC.Collect(); رو فراخونی کنم یعنی اگه کد این جوری باشه :


کد:
            using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
            }

            GC.Collect();

چه متد dispose برای شی file فراخونی بشه یا نه (چه using براش بکار برده بشه یا نه) ، حجم رم از 800 مگ حدودا به 400 مگ کاهش پیدا میکنه . دلیل اش چیه؟
اگه کد اولی باشه یعنی a=null باشه ، تقریبا حجمش برمیگرده سر جای اول اش . البته حدود 7 مگ باز بیشتر اشغال میکنه. این 7 مگ رو هم میشه کاری کرد که برگردوند؟
اون بقیه ی سئوال های پست بالا هم اگه جواب بدین ، ممنون میشم
 

SU-57

Active Member
سلام آقا رامین
به switch ربط نداره
شما کلا switch رو هم که حذف کنید ، میبینید که بازم myLabel اجرا میشه
با break point میتونین روند اجرای کد رو ببینین
من که جوابم رو نگرفتم. چون من اینو خودم می دونم که اگه switch رو هم حذف کنم باز اجرا می شه و توی این کدی که شما دادید هم من بلاک if رو حذف کردم باز کد اجرا می شد. یعنی من می خوام بدونم راه حلی داره که فقط در صورتی که if یا switch درست باشه label ما اجرا بشه یا اینکه همیشه اجرا می شه. اگه همیشه اجرا می شه که استفاده از goto بی مورده و اگه شما راه حلی داری ارائه کن

منظورم کد زیره که شما ارائه کردی و من if رو هم حذف می کنم اجرا می شه

کد:
      int b = 0;
        private void btnLable_Click(object sender, EventArgs e)
        {
            if (b < 1)
            {
                b++;
                goto Label1;
            }

            Label1:
            {
                int a = 10;
                MessageBox.Show(a.ToString());

            }
        }
 

the_king

مدیرکل انجمن
سلام
استاد علی ، من کد :

کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Mokhtar Nameh\mokhtar name 2.divx"))
            {
                string a = file.ReadToEnd();
            }

رو که اجرا میکنم (حجم فایلم حدودا 250 مگ هست) ، بعد از اتمام بلاک ، هیچ چی از منابع و رم آزاد نمیشه و 1 گیگ از رم رو اشغال میکنه با اونکه توی دستور using نوشته و متد dispose رو فراخونی میکنه
چرا؟

فقط بعد از بلاک using ، متد GC.Collect() رو فراخونی میکنم ، اشغال رم به حدود 500 مگ کاهش پیدا میکنه ولی به حالت اولیه اش (قبل از خوندن فایل) که 7 مگ رو اشغال میکرد ، نمیرسه
چی کار باید کنم تا به حالت اولش برگرده؟
بعد اینکه فایل ای که قراره بخونه ، حدود 250 مگ حجمش هست اما چرا موقع خوندن فایل ، حدود 1 گیگ (یعنی 4 برابر بیشتر از حجم خود فایل) در رم رو اشغال میکنه؟!
توی لوا هم همین جوری بود . هم قضیه ی چندین برابر اشغال کردن حجم و هم قضیه ی گربگ کالکتور منتها گربگ الکتور در لوا وقتی فراخونی میشد ، تقریبا همه چیزرو پاک میکرد و حجم رم اشغالی برنامه ، به حالت اولیه ی خودش برمیگشت
-----------------------------
بعد اینکه انجمن چرا چند هفته ای هست هی قاتی میکنه؟
ممنون
هنوز سر Dispose مشکل دارین، همچنان مفهومش رو ربط میدید به حافظه اشیاء NET. در حالی که اصلا چیزی که شما میخواهید آزاد بشه کاری به Dispose نداره. حافظه مدیریت شده داخل ماشین مجازی NET. مسئولیتش با GC ئه، ربطی به Dispose نداره. منابعی که Dispose قراره آزاد کنه فایل ئه که Open شده و اگه برنامه با خطا از روتین در اومد یا یادتون رفت Close اش کنید همینطور باز نمونه و بسته بشه. حافظه اشیائی که با new ساخته میشه که خود GC آزاد می کنه، کاری به Dispose ندارن. اگه لازم بود که string و int و Array رو هم براشون Dispose میذاشتن. Dispose رو طراحی نکردن که باهاش حافظه مدیریت شده رو آزاد کنن. طراحی اش کردن که منابع مدیریت نشده رو آزاد کنن، کاری به مسئولیت های GC نداره، بار چندمه که دارم اینو میگم.
شما یک فایلی رو باز می کنید، یک بافر ایجاد میشه برای خوندنش توسط StreamReader که الزاما حجم بافر اش به اندازه فایل نیست، میتونه به مرور حجم بافر اش زیاد بشه که مربوط به محدودیت های سیستم عامله که چقدر بافر رو بزرگ کنه. لازم هم نیست کل فایل داخلش جا بشه. بعد که تمام و کمال محتویات فایل رو میخونید یک حافظه دیگه ایجاد میشه که کل محتویات فایله و خروجی ئه ReadToEnd خواهد بود، موقتیه و بالاخره آزاد میشه. بعد یک حافظه مجزا برای رشته string میسازید که باز حجمی مجزا میگیره، نمیاد اشاره کنه به حافظه قبلی. حالا ممکنه این بین یک حافظه موقتی برای تبدیل به string هم ایجاد بشه. طبیعیه که با این روتین همچین مصرف حافظه ای باشه.
شما چه متغیر رو null بکنید و چه نکنید و چه Collect بکنید و چه نکنید بالاخره اون حافظه آزاد میشه اما زمانش در هر صورت توسط GC تعیین میشه. هیچ عجله ای برای آزاد کردنش نداره و لزومی هم نداره داشته باشه. اصولا حافظه RAM ای که خالی دست سیستم عامل بمونه هدر رفته است، تلاش سیستم عامل هم بر این نیست که تا میتونه حافظه آزاد بیشتری پیش خودش داشته باشه، اینکار اتلاف منابع ئه. اینکه بخواهید سریع حافظه GC رو آزاد کنین هم کمکی به چیزی نکردین. روی استفاده موثر تر از حافظه و الگوریتم های کارآمد تر متمرکز بشین، نه تغییر دادن روال GC
میدونم روی سرور کار می کنن، اما در جریان ریزه کاریهاش نیستم.
 

the_king

مدیرکل انجمن
جوابش رو پیدا کردم
باید متغییر رشته رو قبل از فراخونی متد GC.Collect() ، باید null کنم تا از رم پاک شه :


کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
                a = null;
            }
          
            GC.Collect();

ولی یه سئوال .
مگه وقتی کنترل برنامه به اتمام بلاک در using در بالا برسه ، اتوماتیک متغییر a که تعریف شده ، اشاره گرش از دست نمیره؟ اگه این طوری باشه (از دست بره) ، دیگه نیازی به null کردن متغییر نیست و اگه از دست نره ، پس من قبلا در یه مقاله ای خونده بودم که وقتی متغییرها به اتمام بلاک برسن ، پاک میشن (که لینک اون مقاله رو هم بهتون دادم)
الان متغییر file در بالا ، حجم خاصی از رم رو اشغال نمیکنه . همش واسه اون متغییر a هست . متوجه ی کاربرد متد dispose در StreamReader نشدم . منابع سیستمش چیزی از رم اشغال نکرد که !
حالا سئوال مهم اینه که وقتی GC.Collect(); رو فراخونی نکنم ، حدود 800 مگ از رم اشغال میشه (این یه فایل دیگه با حجم 200 مگ هست) ولی اگه بدون null کردن متغییر a متد GC.Collect(); رو فراخونی کنم یعنی اگه کد این جوری باشه :


کد:
            using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
            }

            GC.Collect();

چه متد dispose برای شی file فراخونی بشه یا نه (چه using براش بکار برده بشه یا نه) ، حجم رم از 800 مگ حدودا به 400 مگ کاهش پیدا میکنه . دلیل اش چیه؟
اگه کد اولی باشه یعنی a=null باشه ، تقریبا حجمش برمیگرده سر جای اول اش . البته حدود 7 مگ باز بیشتر اشغال میکنه. این 7 مگ رو هم میشه کاری کرد که برگردوند؟
اون بقیه ی سئوال های پست بالا هم اگه جواب بدین ، ممنون میشم
این اصلا الگوریتم کارآمدی نیست که GC بخواد مدام هر شیء ای رو چک کنه که آیا الان آزاد شدنی هست یا نیست، به همین جهت بصورت دوره ای و با وقفه این مساله رو بررسی می کنه. اینکه مدتی طول بکشه که حافظه شیء ای آزاد بشه کاملا طبیعیه. و آزاد شدن حافظه هم به این معنی نیست که هر تعداد page گرفته شده عینا پس داده بشه. حفظ کارایی و کاهش سربار خیلی مهمتر از اون 7 مگابایت ئه، سیستم عامل نمیاد کارایی مدیریت حافظه رو فدای چند مگابایت ناقابل کنه. یک عالمه پروسه در سیستم هست که مدام حافظه میخوان و یه لحظه بعد دیگه نمیخوان. در نظر بگیرید که مدام برای ساختن یک متغیر page از سیستم عامل گرفته بشه و باز بابت خارج شدن از روتین و از بین رفتن حافظه متغیر اون page آزاد بشه، هی گرفتن و آزاد کردن خودش سربار ایجاد می کنه. برای همین همچین روتین سفت و سختی اجرا نمیشه. حافظه وقتی از پروسه گرفته میشه که یا مدت زیادی از بلااستفاده بودنش گذشته باشه و یا سیستم عامل کمبود حافظه آزاد پیدا کنه. حافظه آزاد وقتی ارزش داره که پروسه دیگه ای بهش نیاز داشته باشه، حافظه آزاد و خالی به تنهایی ارزشی نداره. اون هفت مگابایت رو از پروسه تون بگیره که چیکارش کنه؟
 

the_king

مدیرکل انجمن
من که جوابم رو نگرفتم. چون من اینو خودم می دونم که اگه switch رو هم حذف کنم باز اجرا می شه و توی این کدی که شما دادید هم من بلاک if رو حذف کردم باز کد اجرا می شد. یعنی من می خوام بدونم راه حلی داره که فقط در صورتی که if یا switch درست باشه label ما اجرا بشه یا اینکه همیشه اجرا می شه. اگه همیشه اجرا می شه که استفاده از goto بی مورده و اگه شما راه حلی داری ارائه کن

منظورم کد زیره که شما ارائه کردی و من if رو هم حذف می کنم اجرا می شه

کد:
      int b = 0;
        private void btnLable_Click(object sender, EventArgs e)
        {
            if (b < 1)
            {
                b++;
                goto Label1;
            }

            Label1:
            {
                int a = 10;
                MessageBox.Show(a.ToString());

            }
        }
خیلی مهمه که اول کاربرد مورد رو بشناسید و بعد برایش مثال بزنین، مخصوصا goto. شاید صد تا مثال بزنین که برای هیچکدوم نه goto مناسب باشه و نه استفاده اش لزومی داشته باشه. همین شرایط برای for و do while و while و ? : و ... هم هست اما برخلاف goto هیچکدوم کد رو پیچیده نمی کنند. هر کدوم شون برای کاربرد هایی خیلی مناسب اند و برای کاربرد های دیگه نامناسب و ناکارآمد. اگر خواستید برای کنترل روال اجرا با if و do while و for و break و ... 100 ساعت تمرین کنید برای goto یک ساعت هم زیاده، کاربرد عملی اش صرفا در شرایط خاصی در بلاک های تو در تو ئه که با break و return کنترل شون دشواره. break اجازه نمیده فرضا در حلقه های تو در تو از حلقه داخلی به خارج از حلقه خارجی بپرید، اینجا goto میتونه مفید باشه، اما اینکه هی از اینجا به اونجا با goto جابجا بشید اصلا توصیه نمیشه. استفاده نابجا و افراطی ازش هم کد رو پیچیده می کنه و هم عادت به نوشتن کد های ساده و روان رو از برنامه نویس میگیره. کلا ازش اجتناب کنید مگر اینکه مجبور باشید. اگر الگوریتم به خوبی طراحی بشه تقریبا هیچوقت هم مجبور نخواهید شد از goto استفاده کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من که جوابم رو نگرفتم. چون من اینو خودم می دونم که اگه switch رو هم حذف کنم باز اجرا می شه و توی این کدی که شما دادید هم من بلاک if رو حذف کردم باز کد اجرا می شد. یعنی من می خوام بدونم راه حلی داره که فقط در صورتی که if یا switch درست باشه label ما اجرا بشه یا اینکه همیشه اجرا می شه. اگه همیشه اجرا می شه که استفاده از goto بی مورده و اگه شما راه حلی داری ارائه کن

منظورم کد زیره که شما ارائه کردی و من if رو هم حذف می کنم اجرا می شه

کد:
      int b = 0;
        private void btnLable_Click(object sender, EventArgs e)
        {
            if (b < 1)
            {
                b++;
                goto Label1;
            }

            Label1:
            {
                int a = 10;
                MessageBox.Show(a.ToString());

            }
        }

سلام آقا رامین
استاد علی در پست بالا جواب دادن و کاملا درست اشاره کردن
label زیاد کارایی نداره . من فقط در یه مقاله خونده بودم ، گفتم در حد اینکه گفته باشم و کاربر از این مسئله آگاه باشه و خالی از عریضه نباشه بگم . کلا ارزش تمرین بیشتر ااز چند دقیقه رو نداره . متوجه نشدین هم اصلا اشکال نداره . کلا مبحث حتی متوسطی (و حتی ضعیف) هم در برنامه نویسی نیست
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
این اصلا الگوریتم کارآمدی نیست که GC بخواد مدام هر شیء ای رو چک کنه که آیا الان آزاد شدنی هست یا نیست، به همین جهت بصورت دوره ای و با وقفه این مساله رو بررسی می کنه. اینکه مدتی طول بکشه که حافظه شیء ای آزاد بشه کاملا طبیعیه. و آزاد شدن حافظه هم به این معنی نیست که هر تعداد page گرفته شده عینا پس داده بشه. حفظ کارایی و کاهش سربار خیلی مهمتر از اون 7 مگابایت ئه، سیستم عامل نمیاد کارایی مدیریت حافظه رو فدای چند مگابایت ناقابل کنه. یک عالمه پروسه در سیستم هست که مدام حافظه میخوان و یه لحظه بعد دیگه نمیخوان. در نظر بگیرید که مدام برای ساختن یک متغیر page از سیستم عامل گرفته بشه و باز بابت خارج شدن از روتین و از بین رفتن حافظه متغیر اون page آزاد بشه، هی گرفتن و آزاد کردن خودش سربار ایجاد می کنه. برای همین همچین روتین سفت و سختی اجرا نمیشه. حافظه وقتی از پروسه گرفته میشه که یا مدت زیادی از بلااستفاده بودنش گذشته باشه و یا سیستم عامل کمبود حافظه آزاد پیدا کنه. حافظه آزاد وقتی ارزش داره که پروسه دیگه ای بهش نیاز داشته باشه، حافظه آزاد و خالی به تنهایی ارزشی نداره. اون هفت مگابایت رو از پروسه تون بگیره که چیکارش کنه؟

ممنون استاد علی
الان یعنی کاربرد dispose در اینجا مثل متد close شه؟ همین؟
بعد اینکه وقتی یه متغییر محلی به آخر بلاک اش میرسه ، null نمیشه؟ یعنی اشارهخ گرش رو از دست نمیده اتوماتیک؟ اگه قراره اشاره گرش رو از دست نده اولا که چرا جوری طراحی کردن کمپایلر رو که در خارج از بلاک و محدوده اش پس دیگه در دسترس نباشه و دوما در این صورت ، با متغییر سراسری ، فرقی نباید داشته باشه . اتفاقا تعریف متغییر سراسری بهتره چون هر دو اشاره گرشون رو از دست نمیدن ولی متغییر سراسری همیشه در دسترس هه
سوم اینکه اولا ، علت اینکه چرا خوندن یه فایل 200 مگابایتی ، به 800 مگابایت نیاز داره رو هنوز متوجه نشدم (مگه خوندن یک چیز ، به اندازه ی همون چیز نباید فضا اشغال کنه؟) و همینطور علت اینکه وقتی GC.Collect رو (بدون null کردن متغییر a) فراخونی میکردم ، فضای اشغالی نصف میشد و از 800 مگ به 400 مگ کاهش میافت؟ (به این معناست که متغییر file حدود 400 مگ فضا اشغال میکرد؟)
---------------------------
بعد هم اینکه فرق برنامه ی 32 بیتی و 64 بیتی ، فقط توی اندازه ی اشاره گرشون هست؟ بنابراین 64 بیتی ها فقط توی اندازه ی استفاده از رم ، محدودیت ندارن؟ و اینکه چرا ویندوز 32 بیتی ، فقط تا حدود زیر 4 گیگ رم رو پشتیبانی میکنن؟ به این دلیل هه که چون تا عدد ۴۲۹۴۹۶۷۲۹۶ داخل 32 بیت حداکثر جا میگیره ، پس تا این شماره از خونه ی رم که حداکثر 4.2 گیگ از آدرس خونه میشه رو فقط ساپورت میکنن؟ اگه آره ، اما پس چرا ویندوزهای 32 بیتی متغییر ان؟ یعنی من توی my computer شون پروپرتیس رو میزدم ، یکی حدود 3.5 گیگ رم رو میشناخت . یکی حدود 3.8 گیگ و ... کلا متفاوت بودن ولی هیچ کدوم تا 4.2 گیگ رو نمیشناخت . تفاوت شون فقط توی میزان استفاده از رم هه؟ در استفاده از پردازنده ، برنامه ی 32 و 64 بیتی که فرقی ندارن؟ دارن؟
و سر آخر هم اینکه چرا خود ویژال استودیو ، برنامه ای 32 بیتی هست؟! در زمونه ای که اغلب نرم افزارهای بزرگ و سنگین مثل محصولات آدوب و ... نرم افزاری جز 64 بیتی ارائه نمیدن و حتی مجموعه ی نرم افزارهای office مایکروسافت که بسیار کم ارزش تر از نرم افزاری مثل ویژال استودیو باید باشه ، نسخه ی 64 بیتی دارن ، خود ویژال استودیو چرا فقط 32 بیتی هست؟ یعنی ویژال استودیو از 4 گیگ رم بیشتر نمیتونه استفاده کنه . درسته؟
calculator ویندوز هم 64 بیت هه :green:
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون استاد علی
الان یعنی کاربرد dispose در اینجا مثل متد close شه؟ همین؟
بعد اینکه وقتی یه متغییر محلی به آخر بلاک اش میرسه ، null نمیشه؟

نه، null نمیشه، خود متغیر ئه حذف میشه، فقط مساله اینه که متغیر یک اشاره گر ئه و حذف شدن روی اون حافظه بزرگ شیء که علاقه مند هستید آزاد کنید تاثیر آنی نداره. null شدن به این معنا است که خود متغیر رو هنوز داشته باشیم که حالا داخلش مقدار null رو ثبت کنیم، اما وقتی خود متغیر رو داریم حذف می کنیم دیگه متغیری نیست که مقدار null داخلش قرار بدیم.

یعنی اشارهخ گرش رو از دست نمیده اتوماتیک؟ اگه قراره اشاره گرش رو از دست نده اولا که چرا جوری طراحی کردن کمپایلر رو که در خارج از بلاک و محدوده اش پس دیگه در دسترس نباشه و دوما در این صورت ، با متغییر سراسری ، فرقی نباید داشته باشه . اتفاقا تعریف متغییر سراسری بهتره چون هر دو اشاره گرشون رو از دست نمیدن ولی متغییر سراسری همیشه در دسترس هه

چرا، بصورت خودکار اشاره گر از دست میره، هر متغیری فقط در محدوده بلاک ای اعتبار داره که تعریف شده. به محض خروج از اون بلاک اشاره گر حذف میشه و از دست میره. متغیر سراسری هم حقیقتا همینطوره فقط بلاک اش خیلی بزرگه.

سوم اینکه اولا ، علت اینکه چرا خوندن یه فایل 200 مگابایتی ، به 800 مگابایت نیاز داره رو هنوز متوجه نشدم (مگه خوندن یک چیز ، به اندازه ی همون چیز نباید فضا اشغال کنه؟) و همینطور علت اینکه وقتی GC.Collect رو (بدون null کردن متغییر a) فراخونی میکردم ، فضای اشغالی نصف میشد و از 800 مگ به 400 مگ کاهش میافت؟ (به این معناست که متغییر file حدود 400 مگ فضا اشغال میکرد؟)

روال اجرا رو در نظر بگیرید، فقط نتیجه کد رو که نبینید. a = 4 + 5 که از همون اول مقادیر رو در a جمع نمی کنه که، اول در یک حافظه دیگه ای 5 + 4 محاسبه میشه و بعد نتیجه کپی میشه در a. همه چی کپی ئه. شما وقتی فایلی رو برای خوندن باز می کنید در چی خونده بشه؟ مستقیم در string a ؟ نمیشه که، هنوز روال اجرا اصلا به a نرسیده، بماند که اصلا نوع داده a هم مناسب خوندن یکسری byte از فایل نیست. اول در بافر خونده میشه، اون بافر خودش حافظه میخواد. بعد متد ReadToEnd اجرا میشه، ReadToEnd باید خروجی بده، بافر که اندازه کل فایل نیست و نمیتونه خروجی باشه، یک حافظه جدا میخواد، بار ها در بافر میخونه و اضافه می کنه به متغیری که خروجی ReadToEnd خواهد بود. بعد تازه از ReadToEnd باید آرایه بایتی تبدیل بشه به رشته که بره داخل a ثبت بشه. همه چی کپی ئه، مدام داره حافظه جدید ایجاد میشه. همه حافظه موقتی های چون دیگه ارجاعی بهشون نیست آزاد میشن ولی GC برای اینکار عجله نداره، به تدریج آزادشون می کنه.
بعد هم اینکه فرق برنامه ی 32 بیتی و 64 بیتی ، فقط توی اندازه ی اشاره گرشون هست؟ بنابراین 64 بیتی ها فقط توی اندازه ی استفاده از رم ، محدودیت ندارن؟ و اینکه چرا ویندوز 32 بیتی ، فقط تا حدود زیر 4 گیگ رم رو پشتیبانی میکنن؟ به این دلیل هه که چون تا عدد ۴۲۹۴۹۶۷۲۹۶ داخل 32 بیت حداکثر جا میگیره ، پس تا این شماره از خونه ی رم که حداکثر 4.2 گیگ از آدرس خونه میشه رو فقط ساپورت میکنن؟

سوالاتی می پرسید که ربطی به #C و این تاپیک نداره.
وقتی آدرس حافظه 64 بیتی باشه هر مقداری که با حافظه در ارتباطه هم 64 بیتی ئه، چه آدرس مستقیم حافظه و چه آدرس نسبی (Offset) و چه متغیری که مقدار حافظه رو نشون میده و ...
محدودیت که همه چی محدود ئه، هیچ چیزی نامحدود نیست، 64 بیتی هم مثل 32 بیتی محدودیت داره، فقط 64 بیتی فضای آدرس اش بزرگتره و در نتیجه حافظه خیلی بیشتری رو میتونه آدرس دهی کنه و محدودیتش از 32 کمتره.
اگه آره ، اما پس چرا ویندوزهای 32 بیتی متغییر ان؟ یعنی من توی my computer شون پروپرتیس رو میزدم ، یکی حدود 3.5 گیگ رم رو میشناخت . یکی حدود 3.8 گیگ و ... کلا متفاوت بودن ولی هیچ کدوم تا 4.2 گیگ رو نمیشناخت .

مربوط به همون 2 به توان 32 ئه اما حافظه تقسیم میشه. اولا فضای آدرس حافظه هسته از برنامه های عادی مجزا است، مثلا در سیستم 32 بیتی بصورت عادی فرضا 2GB یا 3GB حافظه به برنامه های عادی اختصاص داده میشه و بقیه 2GB یا 1GB مربوط به خود سیستم عامل و هسته شه، اینا اشتراکی نیستن و با هم قاطی نمیشن. ثانیا قطعاتی مثل کارت گرافیکی یک فضایی از اون حافظه RAM رو همون ابتدا برمیدارن برای خودشون که دیگه قاطی اون حافظه در دسترس نیست. برای همینه که حافظه ای که اعلام میشه یک قسمتی اش کم ئه. و البته طبق محدودیت های طراحی سیستم عامل ویندوز، برنامه های 32 بیتی حداکثر میتوانند 2 گیگابایت حافظه داشته باشند، حتی اگه 30 گیگابایت حافظه موجود باشه.
تفاوت شون فقط توی میزان استفاده از رم هه؟ در استفاده از پردازنده ، برنامه ی 32 و 64 بیتی که فرقی ندارن؟ دارن؟

چرا فرق داره، بخشی اش بحث معماری پردازنده است که نه تخصص منه و نه ارتباطی به برنامه نویسی داره چون ساختار درونی پردازنده است ولی کلا پردازنده در دو حالت 32 بیتی و 64 بیتی کار می کنه که ممکنه 32 بیتی رو با مدار های مجزا اجرا کنه یا بصورت شبیه سازی با مدار های 64 بیتی که مرسوم تره که به همین جهت هم حداکثر کارایی اش در مود 64 بیتی میشه. اما در هر حال نمیتونه همزمان هر دو تا مود اجرا رو داشته باشه، سوئیچ لحظه ای عملی نیست که بخواد هی بین 32 و 64 بیت سوئیچ کنه. به همین جهت سیستم عامل 64 بیتی فقط در حالت 64 بیتی ئه و برای اجرای برنامه 32 بیتی در سیستم عامل 64 بیتی از شبیه ساز استفاده می کنه که بهش WOW64 میگن.

و سر آخر هم اینکه چرا خود ویژال استودیو ، برنامه ای 32 بیتی هست؟! در زمونه ای که اغلب نرم افزارهای بزرگ و سنگین مثل محصولات آدوب و ... نرم افزاری جز 64 بیتی ارائه نمیدن و حتی مجموعه ی نرم افزارهای office مایکروسافت که بسیار کم ارزش تر از نرم افزاری مثل ویژال استودیو باید باشه ، نسخه ی 64 بیتی دارن ، خود ویژال استودیو چرا فقط 32 بیتی هست؟ یعنی ویژال استودیو از 4 گیگ رم بیشتر نمیتونه استفاده کنه . درسته؟
calculator ویندوز هم 64 بیت هه :green:
ساختن برنامه 64 بیتی خیلی سخت نیست، اگه کد برنامه اصولی نوشته بشه فقط با یک تنظیم زمان کامپایل خروجی 64 بیتی میده، پس اصلا برای مایکروسافت ساختن نسخه 64 بیتی کار سختی نیست.
اما به دلایلی اینکار مفید نیست. اولا اگه بخواد 64 بیتی باشه امکان ارتباط با خیلی از کمپوننت ها و کتابخانه های کلاسیک رو از دست میده، چون فقط نسخه 32 بیتی دارند و اصلا قابلیت ارتباط شون در مود حافظه 64 بیتی نیست. ثانیا ویژوال استدیو برای خودش داره اجرا میشه، 32 بیتی بودنش کاری به اجرای کد برنامه شما که نداره. به همین جهت اگر قراره از مزیت 64 بیتی بودن استفاده کنه باید به جهت منفعت خودش باشه، نه برنامه شما. فرضا فتوشاپ خیلی از 64 بیتی بودن منفعت می بره، چون برای مصرف حافظه اش میتونه خیلی بالا باشه ولی پروسه ویژوال استدیو بیشتر از 2 گیگابایت بدردش نمیخوره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
نه، null نمیشه، خود متغیر ئه حذف میشه، فقط مساله اینه که متغیر یک اشاره گر ئه و حذف شدن روی اون حافظه بزرگ شیء که علاقه مند هستید آزاد کنید تاثیر آنی نداره. null شدن به این معنا است که خود متغیر رو هنوز داشته باشیم که حالا داخلش مقدار null رو ثبت کنیم، اما وقتی خود متغیر رو داریم حذف می کنیم دیگه متغیری نیست که مقدار null داخلش قرار بدیم.


چرا، بصورت خودکار اشاره گر از دست میره، هر متغیری فقط در محدوده بلاک ای اعتبار داره که تعریف شده. به محض خروج از اون بلاک اشاره گر حذف میشه و از دست میره. متغیر سراسری هم حقیقتا همینطوره فقط بلاک اش خیلی بزرگه.

ممنون استاد علی
الان من متوجه نشدم
الان منظورتون اینه که بعد از بلاک ، متغییرحذف میشه ولی اشاره گرش باقی میمونه؟
اگه خود متغییره حدف بشه بعد از بلاک ، دیگه اشاره گر توی چی باقی میمونه؟!!
اشاره گرش هم باید حذف بشه دیگه!
یا اینکه منظورتون اینه که بعد از بلاک ، متغییر و اشاره گرش با هم حذف میشن؟
اگه این طوره ، پس چرا در کد زیر :

کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
            }

            GC.Collect();
وقتی متغییر a را null نکردم ، و بعد که GC.Collect() فراخونی شد ، شی a را آزاد نکرد؟ فقط وقتی آزاد میکنه که شی a را null کنم

روال اجرا رو در نظر بگیرید، فقط نتیجه کد رو که نبینید. a = 4 + 5 که از همون اول مقادیر رو در a جمع نمی کنه که، اول در یک حافظه دیگه ای 5 + 4 محاسبه میشه و بعد نتیجه کپی میشه در a. همه چی کپی ئه. شما وقتی فایلی رو برای خوندن باز می کنید در چی خونده بشه؟ مستقیم در string a ؟ نمیشه که، هنوز روال اجرا اصلا به a نرسیده، بماند که اصلا نوع داده a هم مناسب خوندن یکسری byte از فایل نیست. اول در بافر خونده میشه، اون بافر خودش حافظه میخواد. بعد متد ReadToEnd اجرا میشه، ReadToEnd باید خروجی بده، بافر که اندازه کل فایل نیست و نمیتونه خروجی باشه، یک حافظه جدا میخواد، بار ها در بافر میخونه و اضافه می کنه به متغیری که خروجی ReadToEnd خواهد بود. بعد تازه از ReadToEnd باید آرایه بایتی تبدیل بشه به رشته که بره داخل a ثبت بشه. همه چی کپی ئه، مدام داره حافظه جدید ایجاد میشه. همه حافظه موقتی های چون دیگه ارجاعی بهشون نیست آزاد میشن ولی GC برای اینکار عجله نداره، به تدریج آزادشون می کنه.
پس کلا به ساختار متد ReadToEnd برمیگرده که داخلش چه حافظه و متغییرهایی گرفته شد

سوالاتی می پرسید که ربطی به #C و این تاپیک نداره.
وقتی آدرس حافظه 64 بیتی باشه هر مقداری که با حافظه در ارتباطه هم 64 بیتی ئه، چه آدرس مستقیم حافظه و چه آدرس نسبی (Offset) و چه متغیری که مقدار حافظه رو نشون میده و ...
محدودیت که همه چی محدود ئه، هیچ چیزی نامحدود نیست، 64 بیتی هم مثل 32 بیتی محدودیت داره، فقط 64 بیتی فضای آدرس اش بزرگتره و در نتیجه حافظه خیلی بیشتری رو میتونه آدرس دهی کنه و محدودیتش از 32 کمتره.

مربوط به همون 2 به توان 32 ئه اما حافظه تقسیم میشه. اولا فضای آدرس حافظه هسته از برنامه های عادی مجزا است، مثلا در سیستم 32 بیتی بصورت عادی فرضا 2GB یا 3GB حافظه به برنامه های عادی اختصاص داده میشه و بقیه 2GB یا 1GB مربوط به خود سیستم عامل و هسته شه، اینا اشتراکی نیستن و با هم قاطی نمیشن. ثانیا قطعاتی مثل کارت گرافیکی یک فضایی از اون حافظه RAM رو همون ابتدا برمیدارن برای خودشون که دیگه قاطی اون حافظه در دسترس نیست. برای همینه که حافظه ای که اعلام میشه یک قسمتی اش کم ئه. و البته طبق محدودیت های طراحی سیستم عامل ویندوز، برنامه های 32 بیتی حداکثر میتوانند 2 گیگابایت حافظه داشته باشند، حتی اگه 30 گیگابایت حافظه موجود باشه.

چرا فرق داره، بخشی اش بحث معماری پردازنده است که نه تخصص منه و نه ارتباطی به برنامه نویسی داره چون ساختار درونی پردازنده است ولی کلا پردازنده در دو حالت 32 بیتی و 64 بیتی کار می کنه که ممکنه 32 بیتی رو با مدار های مجزا اجرا کنه یا بصورت شبیه سازی با مدار های 64 بیتی که مرسوم تره که به همین جهت هم حداکثر کارایی اش در مود 64 بیتی میشه. اما در هر حال نمیتونه همزمان هر دو تا مود اجرا رو داشته باشه، سوئیچ لحظه ای عملی نیست که بخواد هی بین 32 و 64 بیت سوئیچ کنه. به همین جهت سیستم عامل 64 بیتی فقط در حالت 64 بیتی ئه و برای اجرای برنامه 32 بیتی در سیستم عامل 64 بیتی از شبیه ساز استفاده می کنه که بهش WOW64 میگن.

ساختن برنامه 64 بیتی خیلی سخت نیست، اگه کد برنامه اصولی نوشته بشه فقط با یک تنظیم زمان کامپایل خروجی 64 بیتی میده، پس اصلا برای مایکروسافت ساختن نسخه 64 بیتی کار سختی نیست.
اما به دلایلی اینکار مفید نیست. اولا اگه بخواد 64 بیتی باشه امکان ارتباط با خیلی از کمپوننت ها و کتابخانه های کلاسیک رو از دست میده، چون فقط نسخه 32 بیتی دارند و اصلا قابلیت ارتباط شون در مود حافظه 64 بیتی نیست. ثانیا ویژوال استدیو برای خودش داره اجرا میشه، 32 بیتی بودنش کاری به اجرای کد برنامه شما که نداره. به همین جهت اگر قراره از مزیت 64 بیتی بودن استفاده کنه باید به جهت منفعت خودش باشه، نه برنامه شما. فرضا فتوشاپ خیلی از 64 بیتی بودن منفعت می بره، چون برای مصرف حافظه اش میتونه خیلی بالا باشه ولی پروسه ویژوال استدیو بیشتر از 2 گیگابایت بدردش نمیخوره.

الان پس ویژال استودیو بیشتر از 2 گیگ نمیتونه استفاده کنه
اما زامارین برای خودش جدا کار میکنه (هر چند در ویژال استودیو هست) . درسته؟
آخه یه بار با زامارین کار میکردم اگه درست به ذهنم برسه ، 5 گیگ فضا اشغال کرده بود و یحتمل باید 64 بیتی باشه
حالا منظورم اینه که برنامه ی 32 بیتی میتونه همون قدر از پردازنده کار بکشه که برنامه ی 64 بیتی میتونه؟ یعنی برنامه ای چون 32 بیتی هست ، امکان داره که نتونه بخاطر 32 بیتی بودن اش از تمام قدرت پردازنده استفاده کنه؟ یا اینکه برنامه های 64 بیتی ، در پردازنده ، سریعتر از برنامه های 32 بیتی پردازش میشن یا اینکه فرقی ندارن؟
 

the_king

مدیرکل انجمن
ممنون استاد علی
الان من متوجه نشدم
الان منظورتون اینه که بعد از بلاک ، متغییرحذف میشه ولی اشاره گرش باقی میمونه؟
اگه خود متغییره حدف بشه بعد از بلاک ، دیگه اشاره گر توی چی باقی میمونه؟!!
اشاره گرش هم باید حذف بشه دیگه!
یا اینکه منظورتون اینه که بعد از بلاک ، متغییر و اشاره گرش با هم حذف میشن؟
متغیر ئه همون اشاره گر ئه دیگه، ذاتا Pointer ئه. مقدار اشاره گر در حافظه متغیر بوده، وقتی متغیری در کار نیست، اشاره گرش کجای حافظه بمونه؟ متغیری که به یک شی اشاره می کنه یک اشاره گر ئه، مقدارش یک آدرس حافظه است. به یک آدرس حافظه اشاره می کنه که نقطه آغاز داده های مربوط به شیء ئه. وقتی متغیر حذف بشه، مقدارش که یک آدرس حافظه است هم حذف شده، شی نه ها، اشاره گرش. شیء فعلا سر جاش در حافظه است. در نتیجه یکی از تعداد ارجاع هایی که به شی ء بوده کم میشه، GC آمار این ارجاع ها رو داره. که هر وقت این تعداد ارجاع ها به صفر برسه و دیگه ارجاعی به شیء مورد نظر نمونه، اون شیء بعد از این قابل دسترسی نیست، پس GC از اون لحظه به بعد مجوز داره به عنوان یک شیء بلامصرف حافظه شو آزاد کنه.
اگه این طوره ، پس چرا در کد زیر :
کد:
using (System.IO.StreamReader file = new System.IO.StreamReader(@"F:\Film\TV\Serial\Istadeh Dar Ghobar\058-istadeh-dar-ghobar-ghesmat-5.mp4"))
            {
                string a = file.ReadToEnd();
            }

            GC.Collect();
وقتی متغییر a را null نکردم ، و بعد که GC.Collect() فراخونی شد ، شی a را آزاد نکرد؟ فقط وقتی آزاد میکنه که شی a را null کنم
شیء ای که در حافظه است و مقدار رشته a داخلش ذخیره شده کاملا مستقل از متغیر a ئه. a عملا مقداری که نگه داشته یک آدرس حافظه است، a یک اشاره گر ئه، شیء اش جدا است. شاید برای string مثال خوبی نباشه اما ممکنه چندین ارجاع به یک شیء باشه که با حذف شدن a هنوز ارجاعی مونده باشه. GC نمیاد برای یک متغیر a روتین بررسی راه بندازه. GC که همون لحظه که از بلاک using در میایید که نمیاد چک کنه خوب حالا چند تا ارجاع به شیء متغیر های داخل using مونده که دوان دوان بره آزاد شون کنه. این اصلا الگوریتم بهینه ای نیست، تعداد بلاک هایی که فقط واسه اجرا شدن یک برنامه ساده در حد Hello World اجرا میشه خیلی زیاده، GC اگه بخواد سر هر بلاک همچین بررسی ای رو انجام بده که نصف وقت پردازنده رو باید اختصاص بدن به GC. شما وقتی میگید GC.Collect معنی اش این نیست که هر چی ارجاع هست برو چک کن ببین شیء شون آزاد کردنی هست یا نه، معنی اش اینه که هر چی شیء رو تا این لحظه به عنوان بلااستفاده شناسایی کردی آزاد کن. مطالب قبلی رو بگردید می بینید که چند بار تکرار کردم که GC.Collect یک درخواست ئه، خواهش ئه، GC مستقل ئه و مستقل کار می کنه، از شما دستور نمی گیره. فرق ئه بین این که بگم "فردا میام" یا بگم "سعی می کنم فردا بیام". در خود MSDN هم گفته با GC.Collect ئه try می کنید، سعی می کنید، تعداد اشیاء در حافظه بیشتر از اونی ئه که بررسی تک تک شون موثر باشه و ارزش داشته باشه.
Use this method to try to reclaim all memory that is inaccessible. It performs a blocking garbage collection of all generations.

پس کلا به ساختار متد ReadToEnd برمیگرده که داخلش چه حافظه و متغییرهایی گرفته شد
فقط اون نیست، همون نوع داده string هم تاثیر داره. تبدیل byte به string خودش روتین مبدل میخواد. a که نمیتونه به یک []byte اشاره کنه. به string اشاره می کنه، پس باید تبدیل داده صورت بگیره.

الان پس ویژال استودیو بیشتر از 2 گیگ نمیتونه استفاده کنه
نه فقط Visual Studio، هیچ پروسه 32 بیتی ای نمیتونه. البته اگه لازم باشه میتونه با چندین پروسه کار کنه و یک حافظه ای رو هم برای استفاده اشتراکی همه نسخه هاش قرار بده که با هم تبادل داده کنند. ممکنه یک برنامه برای اجرای موازی یک روتینی چندین پروسه از خودش رو اجرا کنه.
اما زامارین برای خودش جدا کار میکنه (هر چند در ویژال استودیو هست) . درسته؟
در ویژوال استدیو بودنش رو مطمئن نیستم چون تا حالا بررسی نکردم نحوه اجرا شدن چطوریه اما اگه جزئی از پروسه اصلی ویژوال استدیو باشه نمیتونه حافظه اضافه ای داشته باشه که از محدوده 2GB ئه پروسه فراتر بره.
آخه یه بار با زامارین کار میکردم اگه درست به ذهنم برسه ، 5 گیگ فضا اشغال کرده بود و یحتمل باید 64 بیتی باشه
اگه 64 بیتی باشه که قطعا پروسه جدایی ئه، حتی اگه 5 مگابایت حافظه هم مصرف کنه نمیتونه جزئی از یک پروسه 32 بیتی باشه.

حالا منظورم اینه که برنامه ی 32 بیتی میتونه همون قدر از پردازنده کار بکشه که برنامه ی 64 بیتی میتونه؟ یعنی برنامه ای چون 32 بیتی هست ، امکان داره که نتونه بخاطر 32 بیتی بودن اش از تمام قدرت پردازنده استفاده کنه؟ یا اینکه برنامه های 64 بیتی ، در پردازنده ، سریعتر از برنامه های 32 بیتی پردازش میشن یا اینکه فرقی ندارن؟
تا اونجایی که به معماری پردازنده های مرسوم و سیستم عامل ویندوز مربوطه نمیتونه، یعنی کارایی کد 32 بیتی نمیتونه به اندازه 64 بیتی باشه. صحبت حداکثر حافظه در اختیارش نیست ها، برای سازگاری با پردازنده و محیط اجرای 64 بیتی سربار بهش تحمیل میشه، چه سخت افزاری و چه نرم افزاری. اجرای کد 32 بیتی برای پردازنده 64 بیتی به تنهایی سربار داره، چون از نظر هزینه به صرفه نیست که بیان یک پردازنده رو از ترکیب دو بخش کاملا مستقل 32 بیتی و 64 بیتی بسازند، اقتصادی نیست، بخش 32 بیتی رو با شبیه سازی و تطبیق با محیط 64 بیتی پیاده سازی می کنند. و تطابق اون کد 32 بیتی با پردازنده ای که مدارش ذاتا 64 بیتی ئه سربار ایجاد می کنه، یعنی کارایی کمتر. این تازه بخش سخت افزاری اش بود. در کنارش بحث نرم افزاری مطرحه، ویندوز نمیتونه در محیط 64 بیتی که آدرس ها 64 بیتی اند یک پروسه 32 بیتی رو مستقیم اجرا کنه، از شبیه ساز استفاده می کنه که باز سربار داره.

اما در حالت کلی اصلا حداکثر قدرت پردازنده بدست نمیاد که، یک آمار کلی و حدودی از میزان کارایی پردازنده سیستم تون بگیرید، میبینید که بیشتر وقتش بیکار ئه. این یک معضل جدید نیست، از همون سیستم عامل های ابتدایی همین مساله بوده که پردازنده بیشتر بیکار ئه تا مشغول. معنی اش چیه؟ معنی اش اینه که اگه بشینید کد همه برنامه های روی ویندوز تون رو بازنویسی و بهینه کنید تا بهتر از پردازنده استفاده کنند، نتیجه اش بیکار شدن بیشتر پردازنده است، چون کارشون زودتر تموم میشه. و این هم چیز بدی نیست که بخواهید جلوشو بگیرید.
اون چیزی که شما میخواهید بهش برسید، واقعا اون چیزی نیست که مطلوب ئه. شما باید سعی کنید الگوریتمی پیدا کنید که سریعتر به جواب برسه، یعنی زودتر پردازنده رو بیکار کنه، کمتر وقت پردازنده رو بگیره و پردازنده بیکار تر بشه. نه اینکه طوری از پردازنده کار بکشید که بیشتر اشغال بشه. بیشتر اشغال شدن پردازنده به معنی کارایی بهتر کد شما نیست، کد شما میخواد یک کاری انجام بده، نه اینکه حرارت و توان مصرفی پردازنده رو ببره بالاتر. این مثل اینه که بگیم چطور کار کنیم که بیشتر خسته بشیم. بیشتر خسته شدن به این معنی نیست که بهتر کار می کنیم.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
متغیر ئه همون اشاره گر ئه دیگه، ذاتا Pointer ئه. مقدار اشاره گر در حافظه متغیر بوده، وقتی متغیری در کار نیست، اشاره گرش کجای حافظه بمونه؟ متغیری که به یک شی اشاره می کنه یک اشاره گر ئه، مقدارش یک آدرس حافظه است. به یک آدرس حافظه اشاره می کنه که نقطه آغاز داده های مربوط به شیء ئه. وقتی متغیر حذف بشه، مقدارش که یک آدرس حافظه است هم حذف شده، شی نه ها، اشاره گرش. شیء فعلا سر جاش در حافظه است. در نتیجه یکی از تعداد ارجاع هایی که به شی ء بوده کم میشه، GC آمار این ارجاع ها رو داره. که هر وقت این تعداد ارجاع ها به صفر برسه و دیگه ارجاعی به شیء مورد نظر نمونه، اون شیء بعد از این قابل دسترسی نیست، پس GC از اون لحظه به بعد مجوز داره به عنوان یک شیء بلامصرف حافظه شو آزاد کنه.
شیء ای که در حافظه است و مقدار رشته a داخلش ذخیره شده کاملا مستقل از متغیر a ئه. a عملا مقداری که نگه داشته یک آدرس حافظه است، a یک اشاره گر ئه، شیء اش جدا است. شاید برای string مثال خوبی نباشه اما ممکنه چندین ارجاع به یک شیء باشه که با حذف شدن a هنوز ارجاعی مونده باشه
ممنون استاد علی :rose:
بله میدونستم و قبلا گفته بودین (در واقع سئوالم این نبود)

GC نمیاد برای یک متغیر a روتین بررسی راه بندازه. GC که همون لحظه که از بلاک using در میایید که نمیاد چک کنه خوب حالا چند تا ارجاع به شیء متغیر های داخل using مونده که دوان دوان بره آزاد شون کنه. این اصلا الگوریتم بهینه ای نیست، تعداد بلاک هایی که فقط واسه اجرا شدن یک برنامه ساده در حد Hello World اجرا میشه خیلی زیاده، GC اگه بخواد سر هر بلاک همچین بررسی ای رو انجام بده که نصف وقت پردازنده رو باید اختصاص بدن به GC. شما وقتی میگید GC.Collect معنی اش این نیست که هر چی ارجاع هست برو چک کن ببین شیء شون آزاد کردنی هست یا نه، معنی اش اینه که هر چی شیء رو تا این لحظه به عنوان بلااستفاده شناسایی کردی آزاد کن. مطالب قبلی رو بگردید می بینید که چند بار تکرار کردم که GC.Collect یک درخواست ئه، خواهش ئه، GC مستقل ئه و مستقل کار می کنه، از شما دستور نمی گیره. فرق ئه بین این که بگم "فردا میام" یا بگم "سعی می کنم فردا بیام". در خود MSDN هم گفته با GC.Collect ئه try می کنید، سعی می کنید، تعداد اشیاء در حافظه بیشتر از اونی ئه که بررسی تک تک شون موثر باشه و ارزش داشته باشه.
آها پس مشکل از اینه که GC بعد از هر بلاک ، چک نمیکنه که اشاره گر متغییری از دست رفت یا نرفت ؟ (حتی اگه فراخونی اش کنیم؟)
پس وقتی متغییری رو خودمون null میکنیم فقط چک میکنه؟ یعنی در این حالت ، یه چیزی شبیه رویداد اجرا میشه تا GC بفهمه؟


فقط اون نیست، همون نوع داده string هم تاثیر داره. تبدیل byte به string خودش روتین مبدل میخواد. a که نمیتونه به یک []byte اشاره کنه. به string اشاره می کنه، پس باید تبدیل داده صورت بگیره.

نه فقط Visual Studio، هیچ پروسه 32 بیتی ای نمیتونه. البته اگه لازم باشه میتونه با چندین پروسه کار کنه و یک حافظه ای رو هم برای استفاده اشتراکی همه نسخه هاش قرار بده که با هم تبادل داده کنند. ممکنه یک برنامه برای اجرای موازی یک روتینی چندین پروسه از خودش رو اجرا کنه.

در ویژوال استدیو بودنش رو مطمئن نیستم چون تا حالا بررسی نکردم نحوه اجرا شدن چطوریه اما اگه جزئی از پروسه اصلی ویژوال استدیو باشه نمیتونه حافظه اضافه ای داشته باشه که از محدوده 2GB ئه پروسه فراتر بره.

اگه 64 بیتی باشه که قطعا پروسه جدایی ئه، حتی اگه 5 مگابایت حافظه هم مصرف کنه نمیتونه جزئی از یک پروسه 32 بیتی باشه.


تا اونجایی که به معماری پردازنده های مرسوم و سیستم عامل ویندوز مربوطه نمیتونه، یعنی کارایی کد 32 بیتی نمیتونه به اندازه 64 بیتی باشه. صحبت حداکثر حافظه در اختیارش نیست ها، برای سازگاری با پردازنده و محیط اجرای 64 بیتی سربار بهش تحمیل میشه، چه سخت افزاری و چه نرم افزاری. اجرای کد 32 بیتی برای پردازنده 64 بیتی به تنهایی سربار داره، چون از نظر هزینه به صرفه نیست که بیان یک پردازنده رو از ترکیب دو بخش کاملا مستقل 32 بیتی و 64 بیتی بسازند، اقتصادی نیست، بخش 32 بیتی رو با شبیه سازی و تطبیق با محیط 64 بیتی پیاده سازی می کنند. و تطابق اون کد 32 بیتی با پردازنده ای که مدارش ذاتا 64 بیتی ئه سربار ایجاد می کنه، یعنی کارایی کمتر. این تازه بخش سخت افزاری اش بود. در کنارش بحث نرم افزاری مطرحه، ویندوز نمیتونه در محیط 64 بیتی که آدرس ها 64 بیتی اند یک پروسه 32 بیتی رو مستقیم اجرا کنه، از شبیه ساز استفاده می کنه که باز سربار داره.

اما در حالت کلی اصلا حداکثر قدرت پردازنده بدست نمیاد که، یک آمار کلی و حدودی از میزان کارایی پردازنده سیستم تون بگیرید، میبینید که بیشتر وقتش بیکار ئه. این یک معضل جدید نیست، از همون سیستم عامل های ابتدایی همین مساله بوده که پردازنده بیشتر بیکار ئه تا مشغول. معنی اش چیه؟ معنی اش اینه که اگه بشینید کد همه برنامه های روی ویندوز تون رو بازنویسی و بهینه کنید تا بهتر از پردازنده استفاده کنند، نتیجه اش بیکار شدن بیشتر پردازنده است، چون کارشون زودتر تموم میشه. و این هم چیز بدی نیست که بخواهید جلوشو بگیرید.
اون چیزی که شما میخواهید بهش برسید، واقعا اون چیزی نیست که مطلوب ئه. شما باید سعی کنید الگوریتمی پیدا کنید که سریعتر به جواب برسه، یعنی زودتر پردازنده رو بیکار کنه، کمتر وقت پردازنده رو بگیره و پردازنده بیکار تر بشه. نه اینکه طوری از پردازنده کار بکشید که بیشتر اشغال بشه. بیشتر اشغال شدن پردازنده به معنی کارایی بهتر کد شما نیست، کد شما میخواد یک کاری انجام بده، نه اینکه حرارت و توان مصرفی پردازنده رو ببره بالاتر. این مثل اینه که بگیم چطور کار کنیم که بیشتر خسته بشیم. بیشتر خسته شدن به این معنی نیست که بهتر کار می کنیم.
ممنون
 

the_king

مدیرکل انجمن
ممنون استاد علی :rose:
بله میدونستم و قبلا گفته بودین (در واقع سئوالم این نبود)
آها پس مشکل از اینه که GC بعد از هر بلاک ، چک نمیکنه که اشاره گر متغییری از دست رفت یا نرفت ؟ (حتی اگه فراخونی اش کنیم؟)

ابدا مشکل نیست، این که چک نمی کنه مشکل یا ایراد نیست، همانطور که وجود Fragment در درایو خوب نیست، اما هر فایلی رو درایو بسازید یا کپی کنید یا حذف کنید که نباید فورا درایو Defrag بشه. اگه قرار بود همچین اتفافی بیافته خودش یک مشکل بود. GC این کار رو نمی کنه، کار درستی هم می کنه. هر عملیاتی علاوه بر مزایاش سربار هم داره، باید وقتی انجام بشه که ارزش اون سربار رو داشته باشه.
پس وقتی متغییری رو خودمون null میکنیم فقط چک میکنه؟ یعنی در این حالت ، یه چیزی شبیه رویداد اجرا میشه تا GC بفهمه؟
ممنون
بازم چک نمی کنه. اما چون ارجاعی بهش وجود نداره در لیست اشیاء قابل آزاد سازی قرار داره. وقتی متغیری رو null می کنید تعداد ارجاع ها رو یکی کم کردید و در نتیجه شیء با 0 ارجاع میشه و جزو اشیاء آزاد شدنی میشه. این فرق می کنه با اون بررسی تعداد ارجاع های همه اشیاء در حافظه، اون چک کردن یک روال دیگه است. و باز هم به این مساله توجه کنید که آزاد کردن حافظه شیء به این معنی نیست که حتما حافظه بلامصرف پروسه آزاد بشه. و باز به این معنی نیست که آزاد کردن اون حافظه کار بجا و مورد نیازی بوده باشه. خیلی کارها می توانید انجام بدید که یا اصلا لازم نیست یا زمان مناسبی برای انجامش نیست. فرضا شستن بشقاب ها، می توانید بگید هر کی غذاش تموم شد همون لحظه بشقابش شسته بشه، یا می توانید بگید وقتی همه غذاشون تموم شد بشقاب ها شسته بشه یا می توانید بگید هر شب فلان ساعت بشقاب های کثیف شسته بشه یا می توانید بگید هر وقت تعداد بشقاب تمیزی برای استفاده به کمتر از فلان تعداد رسید بشقاب ها شسته بشه. اینها همه شون استراتژی های مختلفی هستند، با کارایی و سربار متفاوت. GC هم بر اساس مطالعات و تجربیات موجود یک استراتژی انتخاب کرده که با حداقل سربار بیشترین کارایی رو داشته باشه. اینجا مشکلی وجود نداره که با دستکاری کردنش بخواهید حل کنید. اینکه پروسه شما حافظه آزاد بلااستفاده دستش باشه یا حافظه شیء ای بلامصرف مونده باشه خیلی عادیه، مشکل نیست.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی
برای ساخت ستاپ در ویژال استودیو 2017 باید چی کار کرد؟
من از اکستنشن زیر استفاده کردم :
Microsoft Visual Studio 2017 Installer Projects - Visual Studio Marketplace
ولی اصلا کارایی لازم و آپشن های مورد نیاز را نداره (تنظیم دات نت فریم ورک ای که باید نصب شه و تنظیم page ها و ... رو نداره) . چی کار باید کرد؟ موقع نصب ویژال استودیو ، باید گزینه ای را برای این منظور تیک زد تا نصب شه؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سئوال بعدی اینکه چرا در کد زیر که اعضای آرایه را در حلقه ی for جداگانه null میکنم ، بعد از GC.Collect ، چیزی از حافظه ی اشغالی ، پاک نمیشه :

کد:
int b = 300000;
            Button[] a = new Button[b];

            for (int i = 0; i < a.Length; i++)
            {
                a[i] = new Button();
            }

            for (int i = 0; i < a.Length; i++)
            {
                a[i] = null;
            }

            a = null;
            GC.Collect();

ولی در کد زیر که در یک حلقه این کار رو انجام میدم ، درست انجام میشه؟ :


کد:
int b = 300000;
            Button[] a = new Button[b];

            for (int i = 0; i < a.Length; i++)
            {
                a[i] = new Button();
                a[i] = null;
            }
          
            a = null;
            GC.Collect();

دلیل اش چیه؟
فرقی نباید میکرد

---------------------------------------

بعد اینکه چرا توی یک کلاس control (کلاسی که از کنترل خاصی ارث بری کرد مثل فرم 1 و ...) ، کلاس دیگه ای مینویسیم ، انگار کلا قاتی میکنه یا حداقل مشکلاتی پیش میاد؟ مثلا اون مشکل نشون ندادن دیزاینر بعد از تغییر دات نت فریم وورک که قبلا گفته بودم ، احتمالا بخاطر همینه که توی اون کلاس فرم ، کلاس های دیگه ای هم تعریف کرده بودم
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه راست کلیک در یک دکمه ، چجوری هه؟
من از رویداد MouseClick در یک دکمه استفاده میکنم و از پروپرتی e.Buttons ولی بازم فقط دکمه ی left را میشناسه و دکمه های right یا middle رو که روی کنترل دکمه انجام میدم ، نمیشناسه
 

جدیدترین ارسال ها

بالا