برنامه نویسی

ذخیره سازی در مقابل حافظه در مقابل Calldata

Rate this post

ذخیره سازی:

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

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

اگر اندازه کل این متغیرها کمتر از 32 بایت باشد، آنها به هم متصل می شوند تا همان اسلات متغیر قبلی را اشغال کنند. اگر اینطور نباشد، آنها به اسلات ذخیره سازی موجود بعدی منتقل می شوند. داده ها به صورت متوالی (یعنی یکی پس از دیگری) ذخیره می شوند، که از اسلات های 0 شروع می شود (و به سمت شکاف های 1، 2، 3 و غیره پیش می روند)، به ترتیبی که در قرارداد اعلام شده اند.

در همه موارد، آرایه‌ها و ساختارهای پویا یک اسلات ذخیره‌سازی جدید را اشغال می‌کنند و هر متغیری که بعد از آنها می‌آید مقداردهی اولیه می‌شود تا یک اسلات ذخیره‌سازی جدید را نیز اشغال کند. از آنجایی که اندازه آرایه‌های پویا و ساختارها از پیش ناشناخته است (یعنی تا زمانی که بعداً در قرارداد شما تخصیص داده شوند)، آنها را نمی‌توان با داده‌هایشان در بین متغیرهای حالت دیگر ذخیره کرد. به جای اینکه 32 بایت را اشغال کنند، فرض می شود که 32 بایت را اشغال می کنند، و اجزای موجود در آنها با شروع در یک شکاف ذخیره سازی متفاوت ذخیره می شوند که با استفاده از هش Keccak-256 محاسبه می شود، همانطور که در بالا توضیح داده شد.

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

حافظه:

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

چهار اسلات 32 بایتی برای حافظه در Solidity وجود دارد که هر کدام دارای محدوده بایت در بایت خاصی هستند که به شرح زیر است:

  1. 64 بایت فضای اسکرچ برای روش های هش.

  2. 32 بایت از اندازه حافظه اختصاص داده شده فعلی، که نشانگر حافظه آزاد است که Solidity همیشه اشیاء جدید را در آن قرار می دهد.

  3. یک شکاف صفر 32 بایتی – که به عنوان مقدار اولیه برای آرایه های حافظه پویا استفاده می شود و هرگز نباید در آن نوشته شود.

به دلیل این تغییرات طراحی است که مواردی وجود دارد که در آن آرایه ها و ساختارها بسته به اینکه در حافظه هستند یا حافظه، از مقادیر متفاوتی فضا استفاده می کنند.

uint8[4] arr;
struct Str {
   uint v1;
   uint v2;
   uint8 v3;
   uint8 v4;
} 
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال، هر یک از آرایه های آرایه و ساختار Str در هر یک از این دو شرایط، 128 بایت حافظه اشغال می کنند (یعنی 4 آیتم، هر کدام 32 بایت). با این حال، به عنوان ذخیره سازی، arr فقط 32 بایت (1 شکاف) را اشغال می کند، در حالی که Str 96 بایت (3 اسلات، هر کدام 32 بایت) را اشغال می کند.

Calldata:

Calldata یک مکان ذخیره‌سازی غیرقابل تغییر و موقت است که در آن آرگومان‌های تابع نگهداری می‌شوند و از نظر عملکرد و پاسخگویی تا حد زیادی مانند حافظه عمل می‌کند. پیشنهاد می شود تا جایی که امکان دارد از calldata استفاده کنید زیرا از ایجاد کپی های غیر ضروری جلوگیری می کند و اطمینان می دهد که داده ها به روز نمی شوند. مقادیر بازگشتی از توابع علاوه بر این می‌توانند شامل آرایه‌ها و ساختارهایی با مکان داده‌های فراخوانی شوند.

ABI قالبی را برای این نوع داده ها مشخص می کند که در مضرب 32 بایت در نظر گرفته می شود و از تعریف ABI (که با فراخوانی های تابع داخلی متفاوت است) پیروی می کند. آرگومان‌های سازنده‌ها کمی متفاوت است، زیرا به‌جای پیشوند نام قرارداد (همچنین در کدگذاری ABI) مستقیماً به انتهای کد قرارداد اضافه می‌شوند.

مقایسه ها:

هنگامی که یک متغیر نوع مرجع (آرایه یا ساختار) تعریف شد، مکان داده برای آن متغیر نیز باید مشخص شود، مگر اینکه متغیر از نوع حالت باشد، در این صورت به طور خودکار به عنوان ذخیره سازی تفسیر می شود. از Solidity نسخه 0.6.9، حافظه و فراخوانی در هر عملکردی مجاز هستند، صرف نظر از اینکه برای عموم قابل مشاهده هستند یا نه (به عنوان مثال خارجی، عمومی و غیره).

به طور مشابه، به اشیاء یا آرایه‌ها در جاوا اسکریپت، تخصیص‌ها یا منجر به کپی‌هایی از داده‌هایی می‌شوند که تولید می‌شوند یا به سادگی به همان قطعه داده ایجاد شده ارجاع می‌دهند:

  • تخصیص بین حافظه و حافظه (یا از داده های فراخوانی) همیشه منجر به ایجاد یک کپی جدید می شود.

  • تکالیف از یک حافظه به حافظه دیگر تنها منجر به ایجاد مراجع می شود. در نتیجه، تغییر یک متغیر حافظه بر همه متغیرهای حافظه دیگر که به همان داده‌های متغیر حافظه تغییر یافته اشاره می‌کنند، تأثیر می‌گذارد.

  • تخصیص از ذخیره سازی به یک متغیر ذخیره سازی محلی نیز تنها یک مرجع به متغیر ذخیره سازی مورد نظر اختصاص می دهد.

  • هر چیز دیگری که به ذخیره سازی اختصاص داده می شود همیشه کپی می شود.

توصیه می شود هنگام انتقال پارامترهای آرایه به توابع به جای حافظه از calldata استفاده کنید زیرا باعث صرفه جویی قابل توجهی در گاز می شود. به عنوان مثال، استفاده از calldata در یک تابع جمع که روی یک آرایه ورودی حلقه می زند، می تواند به طور متوسط ​​حدود 1829 گاز (یا 3.5 درصد) ذخیره کند.

// Gas used: 50992
function func1 (uint[] memory nums) external {
 for (uint i = 0; i < nums.length; ++i) {
    ...
 }
}
// Gas used: 49163
function func2 (uint[] calldata nums) external {
 for (uint i = 0; i < nums.length; ++i) {
    ...
 }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای مطالب بیشتر، من را دنبال کنید – https://linktr.ee/shlokkumar2303

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

همچنین ببینید
بستن
دکمه بازگشت به بالا