اینم یه تجربه پراکنده دیگه!

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

مشکل با متغیر محلی بزرگ

ما یه کد سی داشتیم که یه متغیر local با حجم حدودا ۱۰ کیلو بایت تعریف شده بود و مقدار دهی اولیه شده بود(عکس بود). همیشه کامپایلر به این قسمت از کد که میرسید کلی طول میکشید تا بتونه کد رو کامپایل کنه و همیشه اعصاب ما رو خورد میکرد. تا اینکه یه روز تصمیم گرفتیم مشکل رو حل کنیم. راه حل‌هایی که پیش رومون بود اینها:

  1. متغیر رو کلا حذف کنیم. که خب نمیخواستیم صورت مساله رو حذف کنیم
  2. متغیر رو global میکردیم که خب همه میتونستن تغییرش بدن و برامون بد بود
  3. متغیر رو static کنیم. این تفاوتی برای ما نداشت فقط میخواستیم امتحان کنیم.

خب اول راه دوم رو امتحان کردیم. اتفاقا هم زمان کامپایل کم شد و هم حجم باینری تولید شده. وقتی راه سوم رو هم امتحان کردیم دیدیم که نتیجه با راه دوم یکیه و حجم باینری کم شده و این خوب بود. چون راه دوم ویژگی‌های متغیر local رو داشت و عیب در دسترس بودن برای همه رو هم نداشت.

بررسی چرایی راه‌حل

سوالی که برای ما پیش اومد این بود که چرا یه تغییر اینجوری اینهمه هم توی سرعت هم حجم باینری موثره؟ برای جواب دادن به این ماجرا یکم رفتم تحقیق کردم:

  • همه باینری‌ها از بخش‌های مختلفی تشکلی شدن که اگه assembly یادتون باشه شامل اینهاست
  • متوجه شدم که متغیرهای global توی data segment تعریف میشن و متغیرهای local توی stack segment تعریف میشن.
  • متوجه شدم که متغیرهای static هم توی data segment تعریف میشن.

پس هرچی بود زیر سر data segment بود از اینجا به بعدش بازی شد حدس و گمان در مورد چرایی دوتا اتفاق:
– چرا سرعت کامپیال بیشتر؟ احتمالا به این دلیل که کامپایلر با data segment راحت‌تر کار میکنه تا stack segment. اما این حدس حجم باینری کمتر رو توجیه نمیکنه چون در این دوحالت حجم متغیر ثابت مونده
– چرا حجم باینری کمتر؟ برای اینکار یکم باید یادمون بیاد توی assembly که چطور یه متغیر local تعریف میشه منظورم هست. یه متغیر local عملا اینه که اول یه مقداری توی stack قرار میگیره و در یه مرحله دیگه اون مقدار از stack خارج میشه. که این هم نیاز به کد سمت code segment داره هم نیاز به حافظه سمت stack segment داره.

خب با این حالت ما به حدس دقیق تری از اتفاق پشت پرده رسیدیم. اونم اینه که وقتی متغیر توی data segment قرار میگیره یه بخش توسط کامپایلر تخصیص داده میشه و مقادیر هم توی اون خونه‌ها نوشته میشه. ولی وقتی قرار باشه اون متغیر توی stack segment قرار بگیره هم کد تولید میشه هم حافظه تخصیص داده میشه که منجر به طولانی تر شدن کل روند میشه.

امیدوارم به دردتون خورده باشه
همین!

اینم یه تجربه پراکنده دیگه!

چند شب پیش یکی از دوستان با این سوال به سراغ من اومد:

مشکل اینه که وقتی با malloc یا new یک حافظه تخصیص میدی و با free یا delete حافظه رو برمیگیردونی, اون حافظه شاید بلاک هاش خالی بشه اما توی تسک لیست خالی به عنوان منابع استفاده شده میاره و تا پایان پروسه پاک نمیشه. از دوستانی که آشنایی دارن پیگیری کن ببین جریان چیه. مهمه .

خدا خیرت بده. یه جایی از حافظه نمایی رشد میکه و وقتی خالیش میکنیم (با اینکه از لیست heap سیستم عامل خالی میشه) اما توی لیست پروسه‌ها(مثل نتیجه ps) هنوز به عنوان حافظه استفاده شده هست و حافظه آزاد نمیشه !!!‌ عجیبه . کلی توی اینترنت اینو سوال کردن !!

من که لینوکسم. اما فکر کنم ویندوزم همینه. چون سوالای اینترنت هردوشونه

کلا بخوام سوال رو خلاصه کنم اینجوریه که چرا وقتی حافظه رو به سیستم‌عامل پس میدیم واقعا پس داده نمیشه. من یکم از دانسته‌هام استفاده کردم و یکم هم تحقیقات کردم

پیش‌نیازها

پیش نیازهایی که به نظرم باید بدونیم ایناست:

  • نکته صفر اینکه با توجه به تحقیقات من زیر کلمه کلیدی new از همون malloc استفاده میشه. پس بررسی malloc به تنهایی میتونه جوابی برای ما فراهم کنه.
  • اول اینکه باید بدونیم که وقتی malloc صدا زده میشه چه اتفاقی میفته. کاری که malloc میکنه اینه که heap پروسه رو بهت اختصاص میده. حالا heap توسط سیستم عامل مدیریت میشه و در صورت نیاز به پروسه‌ی شما حافظه بیشتری تخصیص میده.
  • دوم اینکه فضای heap توسط کرنل مدیریت میشه و به اصطلاح نگاشته میشه به یه چیزی به نام Virtual Memory
  • سوم اینکهVirtual Memory نگاشته میشن به چیزی به نام Memory Page که نزدیک به سخت افزار تره
  • چهارم اینکه Memory Page نگاشته میشن بلوک‌های واقعی حافظه. از این مطمئن نیستم اما این نزدکترین لایه به سخت افزاره که من باهاش آشنا هستم.

بررسی مساله

حالا اگه بخوایم مساله رو بررسی کنیم باید به چند‌تا سوال جواب بدیم:

  • اول اینکه malloc چطور عمل میکنه؟ در پیاده‌سازیش ساز و کارش چیه؟
  • دوم اینکه روند افزایش طول Virtual Memory و اضافه شدن Memory Pageها چطوره؟
  • سوم اینکه بعد از پس دادن Memory Pageها سیستم عامل چطور اونها رو از یک پروسه پس میگیره؟

خب جواب سوالا به ترتیب اینا به نظر میرسن:

  • پیاده‌سازی‌های متفاوتی از malloc وجود داره
    • پیاده‌سازی معمولا اون اینطوریه که پس از گرفتن حافظه وقتی free شد معمولا اونها رو به سیستم عامل پس نمیده و نگه میداره که شاید بعدا بخواد دوباره تخصیص بده.
    • دوم اینکه درخواست یک Memory Page جدید توسط دستوراتی مثل mmap و sbrk درخواست یک بلاک بزرگ حافظه میکنه و اون رو بنا به درخواست نرم‌افزار تخصیص میده.
    • بعدش هم اینکه برای اینکه یک Memory Page رو برگردونه به سیستم عامل بایستی تمام حافظه‌هایی که روی اون تخصیص داده شدن برگشت داده بشه. که این هم همیشه اتفاق نمی‌افته.
    • معمولا هم پیاده‌سازی‌ها اینجورین که حافظه‌ای که توسط sbrk افزایش پیدا کرده رو دست نمیزنن(دلیل دقیقش رو نمیدونم) و حافظه‌ای که توسط mmap اضافه شده رو به راحتی برمیگردونن.
  • تقریبا جواب سوال دوم رو هم تا الان دادم. مقدار Virtual Memory توسط glibc کنترل میشه و بوسیله malloc تخصیص داده میشه.
  • جواب سوال سوم هم اینه که کرنل لینوکس همیشه حافظه برگشت داده شده رو برنمیگردونه چون که هزینه داره فقط اون رو علامت میزنه که در صورت نیاز اون رو حذف کنه یا به swap ببره.

راه حل مساله

حالا بریم سراغ مساله اصلی(چرا حافظه برگشت داده شده برگشت نخورده) و توجیهی که براش پیدا کردیم:
* مهمترین دلیل این اتفاق به نظرم malloc هست که حافظه رو نگه داشته و برنگردونده
* دومین دلیلش هم میتونه این باشه که کرنل هنوز Memory Page رو برنداشته و فقط علامت زده

حالا راه حل چیه:
* اول اینکه به کرنل و glibc اعتماد کنیم
* دوم اینکه بیایم و این پارامتر مروبط به malloc رو تنظیم کنیم۴
* سوم اینکه بیایم از یه پیاده‌سازی دیگه برای تخصیص حافظه و آزاد سازی اون استفاده کنیم
* چهارم اینکه بیایم خودمون مستقم از mmap و munmap استفاده کنیم

امیدوارم اینا راه گشای دیگران هم باشه

برای مطالعه بیشتر:

۱

۲

۳

۴

همین!

اینم یه تجربه پراکنده دیگه!

امروز یه قسمت دیگه از کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند» رو اینجا به اشتراک میگذارم. این چهارمین ویدئو هست که فصل ۱۱ رو ارائه میده. این مدت پیدا کردن زمان خلوت توی خونه معزلی شده بود. به همین خاطر دل رو به دریا زدم و گفتم با حضور «حناچه» در پشت صحنه ضبط مکنم. انشالا که خوب شده باشه و بتونم بقیه کتاب رو هم ضبط کنم.

یادتون نره که با کامنت‌هاتون و به اشتراک گذاشتناتون می‌تونید من رو تشویق کنید که بقیه اش رو هم ضبط کنم. هر جا که خواستید اینها رو به اشتراک بگذارید و فقط اسمی از من بیارید.

این ویدئو بصورت همزمان توی وب سایت هایو هم به انتشار رسیده.

ویدئو

در یوتیوب:

در آپارات:

اینم یه تجربه پراکنده دیگه!

امروز یه قسمت دیگه از کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند» رو اینجا به اشتراک میگذارم. این سومین ویدئو هست که فصل ۱۰ رو ارائه میده. نکته اینکه با توجه به اینکه بازخورد کیفیت پایین صدا داشتم سعی کردم که یکم روی کیفیت صدای این قسمت کار کنم. انشالا که بتونم بقیه کتاب رو هم ضبط کنم.

یادتون نره که با کامنت‌هاتون و به اشتراک گذاشتناتون می‌تونید من رو تشویق کنید که بقیه اش رو هم ضبط کنم. هر جا که خواستید اینها رو به اشتراک بگذارید و فقط اسمی از من بیارید.

این ویدئو بصورت همزمان توی وب سایت هایو هم به انتشار رسیده.

ویدئو

در یوتیوب:

در آپارات:

اینم یه تجربه پراکنده دیگه!

خب من این مدت شروع کردم به ضبط چند قسمت ویدئو به فرمت اسکرین کست از کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند». الان میخوام توضیح بدم که این کار رو به چه صورتی انجام دادم.

برای اینکه متن طولانی نشه مطالب در قسمت‌هایی که قسمت‌ها اینها هستن ارائه میشن:

  1. اصلا چطور شروع کنیم.
  2. نرم افزار تولید
  3. بهبود پس از تولید: معمولا کیفیت صدا بهتر میشه و قسمت‌های ناخواسته ویدئو حذف میشه و از این دست چیزها.
  4. انتشار

توی این پست حرف اساسی اینه که از کجا شروع کنیم. شروع کردن حداقل واسه من به شکل زیر اتفاق افتاد.

  • اول از همه مشخص کردم که هدفم چیه؟ به این سوال جواب دادم که میخوام به کجا برسم و اهدافم چیه. این باعث میشه که موضوع و ابزار رو به درستی انتخاب کنم و توی مسیر خیلی گیج نزنم.
  • دوم اینکه موضوعی رو انتخاب کردم که بهش علاقه دارم و ازش لذت میبرم. همچنین توان ارائه اون موضوع رو هم در خودم میدیدم.
  • سعی کردم ابزارها رو بررسی کنم و ابزارهای درست رو انتخاب کنم.

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

برای انتشار ویدئو هم من اول ویدئو رو روی یوتیوب میگذارم و بعدش اون رو به آپارات منتقل میکنم. اینطوری تنها یک بار ویدئو رو آپلود میکنم.

همین!

پ.ن. انشالا در قسمت بعد یکم در مورد نرم‌افزارهای تولید حرف میزنم.

اینم یه تجربه پراکنده دیگه!

امروز یه قسمت دیگه از کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند» رو اینجا به اشتراک میگذارم. این سومین ویدئو هست که فصل ۵ رو ارائه میده. نکته اینکه با توجه به اینکه ویدئو دوم به خوبی استقبال نشد و یکم سعی کردم با توجه به بازخوردهای شما ویدئو رو بهتر کنم. راستی اضافه کنم که من اول اون فصل‌هایی که رو که خودم باهاشون درگیر بودم رو اول می‌گم و بعدش میرم سراغ مابقی فصلها. انشالا که بتونم بقیه کتاب رو هم ضبط کنم.

یادتون نره که با کامنت‌هاتون و به اشتراک گذاشتناتون می‌تونید من رو تشویق کنید که بقیه اش رو هم ضبط کنم. هر جا که خواستید اینها رو به اشتراک بگذارید و فقط اسمی از من بیارید.

این ویدئو بصورت همزمان توی وب سایت هایو هم به انتشار رسیده.

ویدئو

در یوتیوب:

در آپارات:

اینم یه تجربه پراکنده دیگه!

امروز یه قسمت دیگه از کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند» رو اینجا به اشتراک میگذارم. این دومین ویدئو از ۴ ویدئو اوله. راستی بگم که من اول اون فصل‌هایی که رو که خودم باهاشون درگیر بودم رو اول می‌گم و بعدش میرم سراغ مابقی فصلها. پس این پست فصل ۳ کتاب رو ارائه میکنه. انشالا که بتونم بقیه کتاب رو هم ضبط کنم.

یادتون نره که با کامنت‌هاتون و به اشتراک گذاشتناتون می‌تونید من رو تشویق کنید که بقیه اش رو هم ضبط کنم. هر جا که خواستید اینها رو به اشتراک بگذارید و فقط اسمی از من بیارید.

این ویدئو بصورت همزمان توی وب سایت هایو هم به انتشار رسیده.

ویدئو

در یوتیوب:

در آپارات:

اینم یه تجربه پراکنده دیگه!

من گفته بودم که به تولید محتوا صوتی تصویری علاقه پیدا کردم. پس کتاب «۹۷ چیز که یک برنامه نویس بهتر است بداند» که به نظرم محتوای خوبی داشت رو انتخاب کردم. در مرحله اول ۴ فصلش رو ارائه دادم. انشاا… در هفته‌های آتی اونها رو به اشتراک میگذارم. این هم قسمت اوله.

یادتون نره که با کامنت‌هاتون و به اشتراک گذاشتناتون می‌تونید من رو تشویق کنید که بقیه اش رو هم ضبط کنم. هر جا که خواستید اینها رو به اشتراک بگذارید و فقط اسمی از من بیارید.

این ویدئو بصورت همزمان توی وب سایت هایو هم به انتشار رسیده.

ویدئو

در یوتیوب:

در آپارات:

اینم یه تجربه پراکنده دیگه!

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

قبل از شروع بگم که ضبط صدا اصلا کار آسون و کم هزینه‌ای نیست و یافته‌های من جزء کم هزینه ترین روش‌ها برای ضبط صداست.

برای ضبط صدای با کیفیت به چندتا چیز نیاز داریم:
– یه میکروفن خوب: برای گرفتن صدای شما
– یه کارت صدای با کیفیت: برای تبدیل صدای آنالوگ به دیجیتال
– یه محیط مناسب: محیط کم سر و صدا و بدون نویز
– یه نرم‌افزار ویرایشگر: برای ویرایش صدای ضبط شده

انتخاب میکروفن و کارت صدا برای ضبط

اگه سری به بخش میکروفن‌های دیجی کالا بزنید میبینید که قیمت‌ها از چه قراره و اگه یه سر به جمهوری بزنید بیشتر حساب کار دستتون میاد. حالا بعد از اینکه یه میکروفن حرفه‌ای خریدید تازه باید یه کارت صدای حرفه‌ای هم بخرید که بتونه اون میکروفن رو روشن کنه چون استاندارهای میکروفن‌های حرفه‌ای کلا با اون چیزی که حداقل من تا قبلش دیده بودم خیلی فرق داره. هزینه کارت صدا رو هم می‌تونید خودتون سر انگشتی با توجه به قیمت میکروفن در بیارید که به نظرم امروز هزینه حدود ۲ میلیون خواهیم داشت که به نظرم برای یه کاری که آدم رو خوشحال میکنه خیلی هزینه زیادیه.

راه حل مشابه چیه: اول اینکه بریم سراغ میکرفون‌های حرفه‌ای که خروجی صدا دیجیتال داشته باشن یعنی خروجی usb بدن. این باعث میشه که نیاز به کارت صدا هم مرتفع بشه چون کارت صدا توی میکروفن جاسازی شده. بعد از تحقیق متوجه شدم که یا باید برم سراغ هدست‌های گیمینگ که بتونم میکرفون با کیفیت داشته باشم یا باید برم یه سری میکروفن هایی که برای پادکست‌ها و ویدئو کست‌ها استفاده میشه رو پیدا کنم

راه حل مشابه دوم چیه: اینه که شما از یه voice recorder حرفه‌ای استفاده کنید چیزهایی که مثلا شرکت zoom یا tascam تولید میکنن. اینها خیلی خوب هستن اما برای ویدئو همیشه یه دردسر جدید به اسم همزمان کردن صدای ضبط شده و ویدئو رو بوجود میارن که کم دردسری نیست.

با توجه به این موارد خرید میکروفن usb برای من بهتره و با در نظر گرفتن تحقیقاتی که کردم یکی ازبهترین میکروفن ها blue yeti هست که خب پس از مشقات بسیار گفتم یدونه از ممالک کفر برام آوردن

محیط مناسب

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

راه حلی که من پیدا کردم این بود که بیام اول در زمان سکوت صدا ضبط کنم و از اکثر منابع نویز از نظر فیزیکی دوری کنم. دوم اینکه بیام یه چیزی به نام جrecording booth درست کنم که یه جعبه کوچک عایق صوتی شده است که به مقدار قابل توجهی نویز محیط رو کم میکنه و از رسیدن انعکاس‌های نامناسب صدا به میکروفن جلوگیری میکنه. عکس مراحل انجام این کار رو میتونید اینجا ببینید. هزینه تولید این جعبه هم حدودا ۶۰ هزار تومنه که بیشترش مربوط به جعبه پلاستیکیه

نرم افزار ویرایشگر

من به پیشنهاد اهل فن از نرم افزار audacity استفاده میکنم که نرم افزار متن باز و خوبیه. حالا راه‌حلهای تحت ویندوز دیگه‌ای هم احتمالا وجود داره که من ازش خبر ندارم

پیشنهاد برای مطالعه

پیشنهاد میکنم که پست‌های جادی(۱، ۲ و ۳) رو در مورد نحوه ضبط کردنش ببینید و لذت ببرید.

نکته اضافه

برای کیفیت بهتر ضبط شما معمولا نیاز به پاپ فیلتر یا پ گیر دارید که خب در مجموع بهتون هزینه تحمیل میکنه. من پاپ فیلترم رو با یه کارگاه خیاطی«از اینایی که روش گلدوزی میکنن» و یه جوراب زنونه به قیمت ۵ تومن درست کردم.

اینم یه تجربه پراکنده دیگه!

متاسفانه یه مدت میشه که سرم بیش از اندازه شلوغ شده و نرسیدم وبلاگ بنویسم. قبلا در مورد cmake نشوتم و حالا خواستم یکم بیشتر بنویسم.

خب توی این پست سعی میکنم که بگم که توی دنیای واقعی من از cmake چطور میتونم استفاده کنم. توی دنیای واقعی معمولا پروژه از این بخش‌ها تشکیل شده:

  1. یه سری سورس که اصل منطق برنامه اونجا پیاده سازی شده
  2. یه فایل اصلی یا main که تابع اصلی نرم افزار اونجا قرار گرفته
  3. احتمالا یه سری تست که نرم افزار رو بصورت اتوماتیک مورد تست قرار میدن
  4. احتمالا یه سری کتابخانه که بصورت static یا dynamic به کد اضافه میشن.

یه خورده توضیح بدم که توی مcmake معمولا یه چیزی داریم به عنوان خروجی که میتونه از جنس فایل اجرایی باشه یا از جنس کتابخانه. ما با ترکیب کتابخانه‌ها و سورس کدهای موجود فایل اجرایی نهایی رو درست میکنیم. روند کار هم معمولا به این صورته که:
۱٫ سورسهای اصلی بصورت یه کتابخانه static کامپایل میشه
۲٫ فایل اصلی برنامه بصورت یک فایل اجرایی کامپایل شده و به کتابخانه سورس‌های اصلی لینک میشه
۳٫ تست کیسها بصوت یک فایل اجرایی کامپایل شده و به کتابخانه سورس‌هاس اصلی لینک میشه.
۴٫ کتابخانه ها هم به فایل اجرایی اضافه میشن.

حالا اگه مثال بخوایم یه پروژه رو مثال بزنم که ساختار کدش به شکل زیره

فایل CMakeLists.txt این پروژه یه چیزی شبیه این خواهد بود

شامل یک کتابخانه static و دو فایل اجرایی یکی اصل برنامه و دیگری تست برنامه.

همین!