আপনি যখন new
অপারেটর দিয়ে কোনও শ্রেণীর উদাহরণ তৈরি করেন , তখন গাদাটিতে মেমরি বরাদ্দ হয়ে যায়। আপনি যখন new
অপারেটরের সাথে কোনও কাঠামোর উদাহরণ তৈরি করেন সেখানে মেমরিটি বরাদ্দ হয় কোথায়, গাদা বা স্ট্যাকের উপর?
আপনি যখন new
অপারেটর দিয়ে কোনও শ্রেণীর উদাহরণ তৈরি করেন , তখন গাদাটিতে মেমরি বরাদ্দ হয়ে যায়। আপনি যখন new
অপারেটরের সাথে কোনও কাঠামোর উদাহরণ তৈরি করেন সেখানে মেমরিটি বরাদ্দ হয় কোথায়, গাদা বা স্ট্যাকের উপর?
উত্তর:
ঠিক আছে, আসুন দেখুন আমি এটি আরও পরিষ্কার করে তুলতে পারি কিনা।
প্রথমত, অ্যাশ সঠিক: প্রশ্নটি কোথায় মানের ধরণের ভেরিয়েবল বরাদ্দ করা হয় তা নিয়ে নয় । এটি একটি আলাদা প্রশ্ন - এবং যার উত্তর কেবল "স্ট্যাকের উপরে" নয়। এটি এর চেয়ে জটিল (এবং সি # 2 আরও জটিল করে তুলেছে)। আমার এই বিষয়ে একটি নিবন্ধ আছে এবং অনুরোধ করা হলে এটিতে প্রসারিত হবে তবে কেবল অপারেটরের সাথে কাজ করব।new
দ্বিতীয়ত, এগুলি সমস্তই নির্ভর করে আপনি কোন স্তরের কথা বলছেন on আমি সংস্থাপকটি উত্স কোডটি কী করে, আইএল এটি তৈরির শর্তে কী করে তা দেখছি। এটি অনেক বেশি সম্ভব যে JIT সংকলক যথেষ্ট পরিমাণে "যৌক্তিক" বরাদ্দকে অপ্টিমাইজ করার ক্ষেত্রে চতুর কাজ করবে।
তৃতীয়ত, আমি জেনেরিকগুলি উপেক্ষা করছি, বেশিরভাগ কারণেই আমি আসলে উত্তরটি জানি না এবং আংশিক কারণ এটি জিনিসগুলিকে খুব জটিল করে তুলবে।
অবশেষে, এই সমস্তগুলি কেবলমাত্র বর্তমান বাস্তবায়ন সহ। সি # স্পেস এর বেশিরভাগ নির্দিষ্ট করে না - এটি কার্যকরভাবে কার্যকর করার একটি বিবরণ। এমন যারা আছেন যারা বিশ্বাস করেন যে পরিচালিত কোড বিকাশকারীদের সত্যই যত্ন নেওয়া উচিত নয়। আমি নিশ্চিত নই যে আমি এতদূর যাব, তবে এমন এক পৃথিবীর কল্পনা করা মূল্যবান যেখানে বাস্তবে সমস্ত স্থানীয় ভেরিয়েবলগুলি স্তূপে বাস করে - যা এখনও সেই অনুমানের সাথে সামঞ্জস্যপূর্ণ would
new
অপারেটরের সাথে মান ধরণের দুটি পৃথক পরিস্থিতি রয়েছে : আপনি হয় প্যারামিটারলেস কনস্ট্রাক্টর (যেমন new Guid()
) বা একটি প্যারামিটারফুল কনস্ট্রাক্টর (যেমন new Guid(someString)
) কল করতে পারেন । এগুলি উল্লেখযোগ্যভাবে আলাদা আইএল উত্পন্ন করে। কেন তা বোঝার জন্য, আপনাকে সি # এবং সি এল এল স্পেকের তুলনা করতে হবে: সি # অনুসারে সমস্ত মান ধরণের একটি প্যারামিটারলেস কনস্ট্রাক্টর রয়েছে। সিএলআই স্পেক অনুসারে কোনও মান ধরণের প্যারামিটারলেস কনস্ট্রাক্টর নেই। (কিছু সময়ের প্রতিচ্ছবি সহ একটি মান ধরণের নির্মাতাদের আনুন - আপনি কোনও প্যারামিটারলেস পাবেন না))
কারণ এটি ভাষা সামঞ্জস্যপূর্ণ রাখে এটি একটি কন্সট্রাকটর হিসাবে "শূণ্যসমূহ সঙ্গে একটি মান আরম্ভ" চিকিত্সা C # এর জন্য জ্ঞান করে তোলে - আপনি মনে করতে পারেন new(...)
হিসাবে সবসময় একটি কন্সট্রাকটর আহ্বান। সিএলআই-এর পক্ষে এটি আলাদাভাবে চিন্তা করা বোধগম্য হয়, কারণ কল করার কোনও আসল কোড নেই - এবং অবশ্যই কোনও টাইপ-নির্দিষ্ট কোড নেই।
আপনি মানটি আরম্ভ করার পরে আপনি কী করতে যাচ্ছেন তাও এটি একটি পার্থক্য করে। আইএল এর জন্য ব্যবহৃত
Guid localVariable = new Guid(someString);
ব্যবহৃত আইএল থেকে আলাদা:
myInstanceOrStaticVariable = new Guid(someString);
তদ্ব্যতীত, মানটি যদি একটি মধ্যবর্তী মান হিসাবে ব্যবহৃত হয়, উদাহরণস্বরূপ কোনও মেথড কলের জন্য একটি যুক্তি, জিনিসগুলি আবার কিছুটা আলাদা slightly এই সমস্ত পার্থক্য দেখানোর জন্য, এখানে একটি সংক্ষিপ্ত পরীক্ষা প্রোগ্রাম's এটি স্ট্যাটিক ভেরিয়েবল এবং উদাহরণ ভেরিয়েবলের মধ্যে পার্থক্য দেখায় না: আইএল stfld
এবং এর মধ্যে পার্থক্য করতে পারে তবে এগুলি stsfld
সবই।
using System;
public class Test
{
static Guid field;
static void Main() {}
static void MethodTakingGuid(Guid guid) {}
static void ParameterisedCtorAssignToField()
{
field = new Guid("");
}
static void ParameterisedCtorAssignToLocal()
{
Guid local = new Guid("");
// Force the value to be used
local.ToString();
}
static void ParameterisedCtorCallMethod()
{
MethodTakingGuid(new Guid(""));
}
static void ParameterlessCtorAssignToField()
{
field = new Guid();
}
static void ParameterlessCtorAssignToLocal()
{
Guid local = new Guid();
// Force the value to be used
local.ToString();
}
static void ParameterlessCtorCallMethod()
{
MethodTakingGuid(new Guid());
}
}
এখানে অপ্রাসঙ্গিক বিটগুলি বাদ দিয়ে ক্লাসের জন্য আইএল (যেমন নপস):
.class public auto ansi beforefieldinit Test extends [mscorlib]System.Object
{
// Removed Test's constructor, Main, and MethodTakingGuid.
.method private hidebysig static void ParameterisedCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: stsfld valuetype [mscorlib]System.Guid Test::field
L_0010: ret
}
.method private hidebysig static void ParameterisedCtorAssignToLocal() cil managed
{
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: ldstr ""
L_0008: call instance void [mscorlib]System.Guid::.ctor(string)
// Removed ToString() call
L_001c: ret
}
.method private hidebysig static void ParameterisedCtorCallMethod() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0011: ret
}
.method private hidebysig static void ParameterlessCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldsflda valuetype [mscorlib]System.Guid Test::field
L_0006: initobj [mscorlib]System.Guid
L_000c: ret
}
.method private hidebysig static void ParameterlessCtorAssignToLocal() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
// Removed ToString() call
L_0017: ret
}
.method private hidebysig static void ParameterlessCtorCallMethod() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
L_0009: ldloc.0
L_000a: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0010: ret
}
.field private static valuetype [mscorlib]System.Guid field
}
আপনি দেখতে পাচ্ছেন, কনস্ট্রাক্টরকে কল করার জন্য প্রচুর বিভিন্ন নির্দেশাবলী ব্যবহৃত হয়েছে:
newobj
: স্ট্যাকের মান বরাদ্দ করে, একটি প্যারামিটারাইজড কনস্ট্রাক্টরকে কল করে। মধ্যবর্তী মানগুলির জন্য ব্যবহৃত হয়, যেমন কোনও ক্ষেত্রের জন্য বরাদ্দকরণের জন্য বা পদ্ধতি আর্গুমেন্ট হিসাবে ব্যবহার।call instance
: ইতিমধ্যে বরাদ্দকৃত স্টোরেজ অবস্থান ব্যবহার করে (স্ট্যাকটিতে থাকুক বা না থাকুক)। স্থানীয় ভেরিয়েবলকে বরাদ্দ করার জন্য এটি উপরের কোডে ব্যবহৃত হয়। যদি একই স্থানীয় ভেরিয়েবলকে বেশ কয়েকটি new
কল ব্যবহার করে একাধিকবার একটি মূল্য বরাদ্দ করা হয় তবে এটি কেবল পুরানো মানের শীর্ষে ডেটা শুরু করে - এটি প্রতিবার বেশি স্ট্যাকের স্থান বরাদ্দ করে না ।initobj
: ইতিমধ্যে বরাদ্দকৃত স্টোরেজ অবস্থান ব্যবহার করে এবং কেবল ডেটা মুছবে। এটি আমাদের সমস্ত প্যারামিটারলেস কনস্ট্রাক্টর কলগুলির জন্য ব্যবহৃত হয়, যা স্থানীয় ভেরিয়েবলকে অর্পণ করে। পদ্ধতি কলের জন্য, একটি মধ্যবর্তী স্থানীয় পরিবর্তনশীল কার্যকরভাবে চালু করা হয়েছে, এবং এর মান দ্বারা মুছে ফেলা হয় initobj
।আমি আশা করি এটি একই সাথে এটির উপর খানিকটা আলোকপাত করার সময় বিষয়টি কতটা জটিল তা দেখায়। ইন কিছু ধারণাগত অজ্ঞান, এর প্রতি কলের new
স্ট্যাক বরাদ্দ স্থান - কিন্তু আমরা দেখা করেছি, যে কি সত্যিই এমনকি আইএল পর্যায়ে ঘটে নয়। আমি একটি বিশেষ ক্ষেত্রে হাইলাইট করতে চাই। এই পদ্ধতিটি গ্রহণ করুন:
void HowManyStackAllocations()
{
Guid guid = new Guid();
// [...] Use guid
guid = new Guid(someBytes);
// [...] Use guid
guid = new Guid(someString);
// [...] Use guid
}
সেই "যৌক্তিকভাবে" 4 টি স্ট্যাক বরাদ্দ রয়েছে - ভেরিয়েবলের জন্য একটি এবং তিনটি new
কলের প্রত্যেকটির জন্য একটি - তবে বাস্তবে (সেই নির্দিষ্ট কোডের জন্য) স্ট্যাকটি কেবল একবার বরাদ্দ করা হয়, এবং তারপরে একই স্টোরেজ অবস্থানটি পুনরায় ব্যবহার করা হয়।
সম্পাদনা: শুধু পরিষ্কার হবে, কিছু ক্ষেত্রে এটি একমাত্র সত্য হচ্ছে ... বিশেষ করে, এর মান guid
না দৃশ্যমান যদি হতে হবে Guid
কন্সট্রাকটর একটি ব্যতিক্রম, যার কারণে C # এর কম্পাইলার একই স্ট্যাকের স্লট পুনরায় ব্যবহার করতে সক্ষম হয় ছোঁড়ার। আরও বিশদ এবং এর ক্ষেত্রে প্রয়োগ হয় না এমন ক্ষেত্রে মূল্য টাইপ নির্মাণের জন্য এরিক লিপার্টের ব্লগ পোস্টটি দেখুন ।
আমি এই উত্তরটি লেখার ক্ষেত্রে অনেক কিছু শিখেছি - দয়া করে এর কোনও স্পষ্ট না থাকলে স্পষ্টতার জন্য জিজ্ঞাসা করুন!
List<Guid>
3 টি যুক্ত হয়ে কী হবে? এটি 3 বরাদ্দ (একই আইএল) হবে? তবে তাদের কোথাও
guid
কেবল অর্ধ-ওভাররাইট করা হয়েছে কিনা তা বিবেচ্য নয়, যেহেতু এটি দৃশ্যমান হবে না।
কোনও স্ট্রাক্টের ক্ষেত্র সমেত মেমরিটি স্ট্যাক বা গর্তের উপর নির্ভর করে পরিস্থিতি অনুসারে বরাদ্দ করা যেতে পারে। যদি স্ট্রাক্ট-টাইপ ভেরিয়েবল স্থানীয় ভেরিয়েবল বা প্যারামিটার হয় যা কিছু বেনামী প্রতিনিধি বা পুনরাবৃত্ত শ্রেণীর দ্বারা ক্যাপচার করা হয় না, তবে এটি স্ট্যাকের জন্য বরাদ্দ করা হবে। যদি ভেরিয়েবলটি কোনও শ্রেণির অংশ হয়, তবে এটি ক্লাসের মধ্যে স্তূপে বরাদ্দ করা হবে।
যদি স্ট্রাকটি গাদাতে বরাদ্দ দেওয়া হয়, তবে নতুন অপারেটরকে কল করা মেমরির বরাদ্দ করা আসলে প্রয়োজন হয় না। একমাত্র উদ্দেশ্য হ'ল নির্মাণকারীর মধ্যে যা আছে তা অনুসারে ক্ষেত্রের মানগুলি নির্ধারণ করা। যদি কনস্ট্রাক্টরকে না ডাকা হয়, তবে সমস্ত ক্ষেত্র তাদের ডিফল্ট মান (0 বা নাল) পাবে।
একইভাবে স্ট্যাকের জন্য বরাদ্দ স্ট্রাক্টগুলি বাদে, সি # এর জন্য সমস্ত স্থানীয় ভেরিয়েবলগুলি ব্যবহারের আগে কিছু মান নির্ধারণ করা প্রয়োজন, সুতরাং আপনাকে কাস্টম কনস্ট্রাক্টর বা ডিফল্ট কনস্ট্রাক্টর কল করতে হবে (কোনও কনস্ট্রাক্টর যা প্যারামিটার নেয় না সর্বদা উপলভ্য থাকে structs মধ্যে)।
এটিকে সংক্ষিপ্তভাবে বলতে গেলে নতুন স্ট্রাক্টের জন্য ভুল ব্যবহারকারী, নতুনকে কল করা কেবল কনস্ট্রাক্টরকে কল করে। কাঠামোর একমাত্র সঞ্চয় স্থানটি এটির সংজ্ঞা দেওয়া হয়েছে।
এটি যদি সদস্যের পরিবর্তনশীল হয় তবে এটি সংজ্ঞায়িত যেকোন ক্ষেত্রেই সরাসরি সংরক্ষণ করা হয়, যদি এটি স্থানীয় ভেরিয়েবল বা প্যারামিটার হয় তবে এটি স্ট্যাকের মধ্যে সংরক্ষণ করা হয়।
এটি ক্লাসগুলির সাথে বিপরীতে করুন, যেখানে স্ট্রাক্টটি সম্পূর্ণরূপে সংরক্ষণ করা হত যেখানে রেফারেন্স রয়েছে, অন্যদিকে রেফারেন্সটি কোথাও কোথাও রয়েছে ap (এর মধ্যে সদস্য, স্ট্যাকের স্থানীয় / প্যারামিটার)
এটি C ++ তে কিছুটা দেখার জন্য সহায়তা করতে পারে, যেখানে শ্রেণি / কাঠামোর মধ্যে প্রকৃত পার্থক্য নেই। (ভাষাতে একই রকম নাম রয়েছে তবে তারা কেবলমাত্র জিনিসগুলির ডিফল্ট অ্যাক্সেসিবিলিটি উল্লেখ করে) আপনি যখন নতুন কল করেন তখন আপনি গাদা অবস্থানের একটি পয়েন্টার পান, যখন আপনার কোনও পয়েন্টার ছাড়াই রেফারেন্স থাকে তা সরাসরি স্ট্যাকের মধ্যে সংরক্ষণ করা হয় বা অন্যান্য বস্তুর মধ্যে, আলা সি # তে স্ট্রাক্ট করে।
সমস্ত মান ধরণের মতো, স্ট্রাইকগুলি সর্বদা যেখানে ঘোষিত হয়েছিল সেখানে যায় ।
স্ট্রাক্টগুলি কখন ব্যবহার করবেন সে সম্পর্কে আরও তথ্যের জন্য এই প্রশ্নটি এখানে দেখুন । স্ট্রাক্ট সম্পর্কিত আরও কিছু তথ্যের জন্য এবং এই প্রশ্নটি এখানে ।
সম্পাদনা: আমি দূরত্বে উত্তর দিয়েছিলাম যে তারা সবসময় স্ট্যাকের মধ্যে যায়। এটি ভুল ।
আমি সম্ভবত এখানে কিছু মিস করছি তবে কেন আমরা বরাদ্দ সম্পর্কে যত্নশীল?
মান প্রকারগুলি মান দ্বারা পাস হয়;) এবং সুতরাং যেখানে সেগুলি সংজ্ঞায়িত করা হয় তার চেয়ে আলাদা স্কোপে পরিবর্তন করা যায় না। মানটি পরিবর্তন করতে সক্ষম হতে আপনাকে [রেফ] শব্দটি যুক্ত করতে হবে।
রেফারেন্সের ধরণগুলি রেফারেন্স দ্বারা পাস হয় এবং পরিবর্তিত হতে পারে।
অবিচ্ছেদ্য রেফারেন্স ধরণের স্ট্রিং অবশ্যই সর্বাধিক জনপ্রিয়।
অ্যারের বিন্যাস / সূচনা: মানের ধরণ -> শূন্য মেমরি [নাম, জিপ] [নাম, জিপ] রেফারেন্সের ধরণ -> শূন্য মেমরি -> নাল [রেফ] [রেফ]
এ class
বা struct
ঘোষণাটি একটি ব্লুপ্রিন্টের মতো যা রান সময়গুলিতে দৃষ্টান্ত বা বস্তু তৈরিতে ব্যবহৃত হয়। আপনি যদি একটি class
বা struct
পরিচিত ব্যক্তিকে সংজ্ঞায়িত করেন তবে ব্যক্তি হ'ল প্রকারের নাম। আপনি যদি ব্যক্তির একটি পরিবর্তনশীল পি প্রকারের ঘোষণা এবং সূচনা করেন তবে পি বলা হয় ব্যক্তির কোনও অবজেক্ট বা উদাহরণ instance একই ব্যক্তি ধরনের একাধিক দৃষ্টান্ত তৈরি করা যেতে পারে, এবং প্রতিটি উদাহরণ হিসেবে বলা যায় তার মান আলাদা থাকতে পারে properties
এবং fields
।
এ class
একটি রেফারেন্স টাইপ। যখন কোনও বস্তু class
তৈরি করা হয়, বস্তুটি যে ভেরিয়েবলকে নির্ধারিত হয় কেবল সেই মেমরির একটি রেফারেন্স ধরে। যখন বস্তুর রেফারেন্সটি একটি নতুন ভেরিয়েবলকে বরাদ্দ করা হয়, তখন নতুন ভেরিয়েবলটি মূল বস্তুকে বোঝায়। একটি ভেরিয়েবলের মাধ্যমে করা পরিবর্তনগুলি অন্য ভেরিয়েবলে প্রতিফলিত হয় কারণ তারা উভয়ই একই ডেটা উল্লেখ করে।
এ struct
একটি মান ধরণের। যখন একটি struct
তৈরি করা হয়, যে ভেরিয়েবলটি struct
নির্ধারিত হয় তা স্ট্রাক্টের আসল ডেটা ধারণ করে। যখন struct
নতুন ভেরিয়েবলের জন্য বরাদ্দ করা হয়, এটি অনুলিপি করা হয়। নতুন ভেরিয়েবল এবং মূল ভেরিয়েবলের ফলে একই ডেটার দুটি পৃথক অনুলিপি থাকে। একটি অনুলিপিতে করা পরিবর্তনগুলি অন্য অনুলিপিকে প্রভাবিত করে না।
সাধারণভাবে, classes
আরও জটিল আচরণের মডেল হিসাবে ব্যবহার করা হয়, বা এমন কোনও ডেটা যা কোনও class
বস্তু তৈরির পরে পরিবর্তিত হতে পারে । Structs
ছোট ডেটা স্ট্রাকচারের জন্য সেরা উপযুক্ত যা প্রাথমিকভাবে এমন ডেটা ধারণ করে struct
যা তৈরির পরে পরিবর্তিত হওয়ার উদ্দেশ্যে নয় ।
বেশিরভাগ স্ট্রাক্ট যা মান ধরণের হিসাবে বিবেচিত হয়, স্ট্যাকের জন্য বরাদ্দ করা হয়, যখন বস্তুগুলি স্তূপে বরাদ্দ পায়, যখন বস্তুর রেফারেন্স (পয়েন্টার) স্ট্যাকের উপর বরাদ্দ হয়ে যায়।
স্ট্রাকগুলিতে স্ট্রোকগুলি বরাদ্দ পায়। এখানে একটি সহায়ক ব্যাখ্যা:
অতিরিক্ত হিসাবে, ক্লাসগুলি যখন NET এর মধ্যে ইনস্ট্যান্ট করা হয় তখন হিপ বা .NET- র সংরক্ষিত মেমরি স্পেসে মেমরি বরাদ্দ করে। স্ট্যাকগুলিতে বরাদ্দের কারণে তড়িঘড়ি করা হলে স্ট্রাক্টগুলি আরও দক্ষতা অর্জন করে। তদ্ব্যতীত, এটি লক্ষ করা উচিত যে স্ট্রাইকগুলির মধ্যে পাসিং পরামিতিগুলি মান দ্বারা সম্পন্ন হয়।