يقسم الكومة والمكدس java في Java الذاكرة إلى نوعين: أحدهما ذاكرة مكدس والآخر هو ذاكرة كومة.
يتم تخصيص بعض أنواع المتغيرات الأساسية المحددة في الوظائف والمتغيرات المرجعية للكائنات في ذاكرة مكدس الوظيفة. عندما يتم تعريف متغير في كتلة من التعليمات البرمجية ، يخصص Java مساحة الذاكرة للمتغير في المكدس. عندما يتجاوز نطاق المتغير نطاق المتغير ، ستقوم Java تلقائيًا بتقديم مساحة الذاكرة المخصصة للمتغير ، ويمكن استخدام مساحة الذاكرة على الفور على الفور.
يتم استخدام ذاكرة الكومة لتخزين الكائنات والصفائف التي تم إنشاؤها بواسطة New. تتم إدارة الذاكرة المخصصة في الكومة من قبل جامع القمامة التلقائي Java Virtual Machine. بعد إنشاء صفيف أو كائن في الكومة ، يمكن تحديد متغير خاص في المكدس. قيمة هذا المتغير تساوي العنوان الأول للمصفوفة أو الكائن في ذاكرة الكومة. يصبح هذا المتغير الخاص في المكدس متغير مرجعي للمصفوفة أو الكائن. في المستقبل ، يمكنك استخدام المتغير المرجعي في ذاكرة المكدس في البرنامج للوصول إلى الصفيف أو الكائن في الكومة. المتغير المرجعي يعادل اسم الاسم المستعار أو رمز الصفيف أو الكائن.
المتغيرات المرجعية هي متغيرات عادية. عند تحديدها ، يتم تخصيص الذاكرة على المكدس. يتم إصدار المتغيرات المرجعية خارج النطاق عند تشغيل البرنامج. تم تخصيص الصفيف والكائن نفسه في الكومة. حتى إذا تم تشغيل البرنامج خارج كتلة التعليمات البرمجية حيث توجد البيانات التي تستخدم جديدة لإنشاء الصفيف والكائن ، فلن يتم إصدار ذاكرة الكومة التي تشغلها الصفيف ولن يتم إصدار الكائن نفسه. يصبح الصفيف والكائن فقط القمامة عندما لا يكون هناك متغير مرجعي يشير إليه ، ولم يعد من الممكن استخدامه ، ولكن لا يزال يشغل الذاكرة ويتم إصداره بواسطة جامع القمامة في وقت غير مؤكد. هذا هو أيضًا السبب الرئيسي وراء قيام Java بمزيد من الذاكرة. في الواقع ، تشير المتغيرات في المكدس إلى المتغيرات في ذاكرة الكومة ، وهي المؤشر في Java!
كومة ومكدس في جافا
يقسم جافا الذاكرة إلى نوعين: أحدهما هو ذاكرة المكدس والآخر هو ذاكرة كومة.
1. المكدس والكوتين كلا المكانين تستخدمهما Java لتخزين البيانات في ذاكرة الوصول العشوائي. على عكس C ++ ، تدير Java تلقائيًا الكدسات والأكوام ، ولا يمكن للمبرمجين إعداد أكوام أو أكوام مباشرة.
2. ميزة المكدس هي أن سرعة الوصول أسرع من الكومة ، والثانية فقط إلى السجلات الموجودة مباشرة في وحدة المعالجة المركزية. لكن العيب هو أن حجم البيانات وعمره في المكدس يجب أن يكون حتميًا ويفتقر إلى المرونة. بالإضافة إلى ذلك ، يمكن مشاركة بيانات المكدس. تتمثل ميزة الكومة في أنه يمكن تخصيص حجم الذاكرة ديناميكيًا ، ولا يجب إخبار المترجم مقدمًا مقدمًا. سيقوم جامع القمامة من Java تلقائيًا بجمع البيانات التي لم تعد تستخدم. ولكن العيب هو أنه يجب تخصيص الذاكرة ديناميكيًا في وقت التشغيل ، فإن سرعة الوصول أبطأ.
3. هناك نوعان من البيانات في جافا.
واحد هو الأنواع الأساسية (الأنواع البدائية) ، هناك 8 أنواع ، وهي int ، قصيرة ، طويلة ، بايت ، تعويم ، مزدوج ، منطقية ، شار (ملاحظة ،
لا يوجد نوع أساسي من السلسلة). يتم تعريف هذا النوع من التعريف بواسطة نموذج مثل int a = 3 ؛ طويل ب = 255L ؛ ويسمى متغير تلقائي. تجدر الإشارة إلى أن المتغير التلقائي يحتوي على قيم حرفية ، وليس مثيلات من الفصل ، أي ، وليس الإشارات إلى الفصل ، وليس هناك فئة هنا. على سبيل المثال ، int a = 3 ؛ هنا A هو إشارة تشير إلى نوع int ،
أشير إلى القيمة الحرفية لل 3. نظرًا لحجم هذه القيم الحرفية ، يمكن أن يكون عمر هذه القيم الحرفية معروفة (يتم تعريف هذه القيم الحرفية بشكل ثابت في كتلة البرنامج ، وبعد خروج كتلة البرنامج ، تختفي قيمة الحقل).
من أجل متابعة السرعة ، فإنه موجود في المكدس.
بالإضافة إلى ذلك ، فإن ميزة خاصة مهمة للغاية من المكدس هي أنه يمكن مشاركة البيانات الموجودة في المكدس. لنفترض أننا نحدد في نفس الوقت:
int a = 3 ؛
int b = 3 ؛
المعالجة المترجم أولاً int a = 3 ؛ أولاً ، سيؤدي ذلك إلى إنشاء مرجع إلى المتغير A في المكدس ، ثم اكتشف ما إذا كان هناك عنوان ذي قيمة حرفية 3. إذا لم يتم العثور عليه ، فسيفتح عنوانًا ذو قيمة حرفية 3 ، ثم قم بإشارة A إلى عنوان 3. ثم معالجة int B = 3 ؛ بعد إنشاء المتغير المرجعي لـ B ، نظرًا لوجود قيمة حرفية بالفعل 3 في المكدس ، يُشار بشكل مباشر إلى عنوان 3. وبهذه الطريقة ، يشير كلا و B إلى 3 في نفس الوقت.
من المهم بشكل خاص أن نلاحظ أن هذه المرجع الحرفي يختلف عن كائنات الفئة. على افتراض أن مراجع كائنين من الفئة تشير إلى كائن في نفس الوقت ، إذا قام متغير مرجع كائن واحد بتغيير الحالة الداخلية للكائن ، فإن متغير مرجع الكائن الآخر يعكس هذا التغيير على الفور. بدلاً من ذلك ، لن يتسبب تعديل قيمته من خلال مرجع حرفي في تغيير قيمة أخرى وفقًا لذلك. كما في المثال أعلاه ، بعد تحديد قيم A و B ، دع A = 4 ؛ بعد ذلك ، لن تكون B مساوية لـ 4 ، أو تساوي 3. داخل المترجم ، عند مواجهة A = 4 ، ستعيد البحث عما إذا كانت هناك قيمة حرفية تبلغ 4 في المكدس. إذا لم يكن الأمر كذلك ، أعد فتح العنوان لتخزين قيمة 4 ؛ إذا كان موجودًا بالفعل ، فقم مباشرة بتوضيح A إلى هذا العنوان. لذلك ، لن يؤثر التغيير في القيمة A على القيمة ب.
نوع آخر هو بيانات فئة التغليف ، مثل عدد صحيح ، سلسلة ، مزدوجة ، وما إلى ذلك التي تلتف أنواع البيانات الأساسية المقابلة. كل هذه البيانات الفئة موجودة في الكومة. تستخدم Java عبارة جديدة () لعرض المترجم ويقوم فقط بإنشاء ديناميكي فقط حسب الحاجة في وقت التشغيل ، لذلك يكون أكثر مرونة ، ولكن العيب هو أنه يستغرق المزيد من الوقت.
في جافا ، هناك ستة أماكن مختلفة يمكن تخزين البيانات فيها:
1. سجل. هذه هي أسرع مساحة تخزين لأنها تقع في مكان مختلف عن مناطق التخزين الأخرى - المعالج. ومع ذلك ، فإن عدد السجلات محدود للغاية ، لذلك يتم تخصيص السجلات من قبل المترجم وفقًا للمتطلبات. لا يمكنك التحكم بشكل مباشر ، ولا يمكنك أن تشعر بأي علامات على وجود السجل في البرنامج.
2. كومة. تقع بشكل عام RAM ، ولكن مع "مؤشر المكدس" الخاص به ، يمكنك الحصول على الدعم من المعالج. إذا تحرك مؤشر المكدس ، يتم تخصيص ذاكرة جديدة ؛ إذا تحركت ، يتم تحرير تلك الذاكرة. هذه طريقة سريعة وفعالة لتخصيص التخزين ، في المرتبة الثانية فقط للسجلات. عند إنشاء برنامج ، يجب أن يعرف برنامج التحويل البرمجي Java الحجم الدقيق ودورة الحياة لجميع البيانات المخزنة في المكدس ، لأنه يجب أن ينشئ الرمز المقابل من أجل تحريك مؤشر المكدس لأعلى ولأسفل. يحد هذا القيد من مرونة البرنامج ، لذلك على الرغم من تخزين بعض بيانات JA VA على المكدس - وخاصة مراجع الكائنات ، لا يتم تخزين كائنات Java فيه.
3. كومة. تجمع الذاكرة العالمي (موجود أيضًا في ذاكرة الوصول العشوائي) لتخزين ما يسمى كائنات Java. ميزة الكومة هي أن المترجم لا يحتاج إلى معرفة عدد مناطق التخزين التي يجب تخصيصها من الكومة ، ولا تحتاج إلى معرفة المدة التي ستستمر فيها البيانات المخزنة في الكومة. لذلك ، هناك مرونة كبيرة في تخصيص التخزين في الكومة. عندما تحتاج إلى إنشاء كائن ، تحتاج فقط إلى كتابة سطر رمز بسيط في الجديد. عند تنفيذ هذا السطر من الكود ، سيتم تخزينه وتخصيصه تلقائيًا في الكومة. بالطبع ، يجب دفع الرمز المقابل مقابل هذه المرونة. يستغرق الأمر وقتًا أطول لتخصيص التخزين مع الكومة بدلاً من تخزينه باستخدام المكدس.
4. التخزين الثابت. "ثابت" هنا يعني "في وضع ثابت". يخزن التخزين الثابت بيانات البيانات التي كانت موجودة دائمًا عند تشغيل البرنامج. يمكنك استخدام الكلمة الرئيسية الثابتة لتحديد أن عنصرًا معينًا من الكائن ثابت ، لكن كائن Java نفسه لا يتم تخزينه في مساحة التخزين الثابتة.
5. التخزين المستمر. عادة ما يتم تخزين القيم الثابتة مباشرة داخل رمز البرنامج ، ومن الآمن القيام بذلك لأنه لن يتم تغييرها أبدًا. في بعض الأحيان ، في نظام مضمن ، يتم فصل الثابت نفسه عن أجزاء أخرى ، لذلك في هذه الحالة ، من اختياري وضعه في ROM.
6. تخزين غير رام. إذا نجت البيانات تمامًا خارج البرنامج ، فيمكن تركها دون أي تحكم في البرنامج ويمكن أن توجد عندما لا يكون البرنامج قيد التشغيل.
من حيث السرعة ، هناك علاقة على النحو التالي:
سجل <stack <heap <other
"يتم استخراج المقطع أعلاه من" التفكير في جافا ""
السؤال 1:
String Str1 = "ABC" ؛ String Str2 = "ABC" ؛ system.out.println (str1 == str2) ؛ //حقيقي
السؤال 2:
String str1 = سلسلة جديدة ("ABC") ؛ String Str2 = سلسلة جديدة ("ABC") ؛ system.out.println (str1 == str2) ؛ // خطأ شنيع السؤال 3:
السلسلة S1 = "JA" ؛ السلسلة S2 = "VA" ؛ السلسلة S3 = "Java" ؛ السلسلة S4 = S1 + S2 ؛ System.out.println (S3 == S4) ؛ // false system.out.println (S3.equals (S4)) ؛ // true
يتم تخصيص بعض أنواع المتغيرات الأساسية المحددة في الوظيفة والمتغيرات المرجعية للكائن في ذاكرة مكدس الوظيفة.
عندما يتم تعريف متغير في كتلة من التعليمات البرمجية ، يخصص Java مساحة الذاكرة لهذا المتغير في المكدس. عندما يتجاوز نطاق المتغير المتغير ، ستقوم Java تلقائيًا بتصوير مساحة الذاكرة المخصصة للمتغير ، ويمكن استخدام مساحة الذاكرة على الفور على الفور.
يتم استخدام ذاكرة الكومة لتخزين الكائنات والصفائف التي تم إنشاؤها بواسطة New.
تتم إدارة الذاكرة المخصصة في الكومة بواسطة جامع القمامة التلقائي في الجهاز الافتراضي Java.
بعد إنشاء صفيف أو كائن في الكومة ، يمكن تعريف متغير خاص في المكدس ، بحيث تكون قيمة هذا المتغير في المكدس تساوي العنوان الأول للمصفوفة أو الكائن في ذاكرة الكومة ، ويصبح المتغير في المكدس متغير مرجعي للمصفوفة أو الكائن.
المتغير المرجعي يعادل اسمًا مُعطى لصفيف أو كائن. يمكنك استخدام المتغيرات المرجعية في المكدس في البرنامج للوصول إلى الصفيف أو الكائن في الكومة.
على وجه التحديد: المكدس والكومة كلا المكانين تستخدمهما Java لتخزين البيانات في ذاكرة الوصول العشوائي. على عكس C ++ ، تدير Java تلقائيًا الكدسات والأكوام ، ولا يمكن للمبرمجين إعداد أكوام أو أكوام مباشرة.
كومة Java هي منطقة بيانات وقت التشغيل ، تخصص منها الكائنات مساحة. يتم إنشاء هذه الكائنات من خلال تعليمات مثل New و Newarray و anewarray و multianewarray. لا تتطلب إصدار رمز البرنامج بشكل صريح. الكومة مسؤولة عن جمع القمامة. تتمثل ميزة الكومة في أنه يمكنه تخصيص حجم الذاكرة ديناميكيًا ، ولا يجب إخبار العمر بالمترجم مقدمًا ، لأنه يخصص الذاكرة ديناميكيًا في وقت التشغيل. سيقوم جامع القمامة من Java تلقائيًا بجمع البيانات التي لم تعد تستخدم. لكن العيب هو أنه لأنه يحتاج إلى تخصيص الذاكرة ديناميكيًا في وقت التشغيل ، فإن سرعة الوصول أبطأ.
تتمثل ميزة المكدس في أن سرعة الوصول أسرع من الكومة ، والثانية فقط إلى السجلات ، ويمكن مشاركة بيانات المكدس. لكن العيب هو أن حجم البيانات وعمره في المكدس يجب أن يكون حتميًا ويفتقر إلى المرونة. يخزن المكدس بشكل أساسي بعض الأنواع الأساسية من المتغيرات (، int ، قصيرة ، طويلة ، بايت ، تعويم ، مزدوج ، منطقية ، شار) ومقابض الكائن.
ميزة خاصة مهمة للغاية للمكدس هي أنه يمكن مشاركة البيانات الموجودة في المكدس. لنفترض أننا نحدد في نفس الوقت:
int a = 3 ؛
int b = 3 ؛
المعالجة المترجم أولاً int a = 3 ؛ أولاً ، سيقوم بإنشاء مرجع في المكدس مع متغير A ، ثم معرفة ما إذا كانت هناك قيمة 3 في المكدس. إذا لم يتم العثور عليها ، فسيتم تخزينها 3 ثم توجه A إلى 3. ثم Process Int B = 3 ؛ بعد إنشاء المتغير المرجعي لـ B ، نظرًا لوجود بالفعل قيمة 3 في المكدس ، يشير B مباشرة إلى 3. وبهذه الطريقة ، يشير كل من كلا إلى 3 في نفس الوقت. في هذا الوقت ، إذا تم تعيين = 4 مرة أخرى ؛ ثم سيبحث المترجم مرة أخرى عما إذا كانت هناك 4 قيمة في المكدس. إذا لم يكن كذلك ، تخزين 4 والنقطة من A إلى 4 ؛ إذا كان موجودًا بالفعل ، فأرّ إلى هذا العنوان مباشرة. لذلك ، لن يؤثر التغيير في القيمة A على القيمة ب. تجدر الإشارة إلى أن مشاركة البيانات هذه تختلف عن مشاركة المراجع من كائنين يشيران إلى كائن واحد في نفس الوقت ، لأنه في هذه الحالة لن يؤثر تعديل A على B ، يتم ذلك بواسطة المترجم ، الذي يفضي إلى توفير المساحة. يعدل متغير مرجع الكائن الحالة الداخلية لهذا الكائن وسيؤثر على متغير مرجع كائن آخر.
السلسلة هي بيانات تغليف خاصة. يمكن استخدامه:
سلسلة str = سلسلة جديدة ("ABC") ؛ String str = "ABC" ؛ هناك نوعان لإنشاء. الأول هو استخدام جديد () لإنشاء كائن جديد ، سيتم تخزينه في الكومة. يتم إنشاء كائن جديد في كل مرة يطلق عليها.
النوع الثاني هو إنشاء STR متغير إلى كائن فئة السلسلة في المكدس ، ثم معرفة ما إذا كان هناك "ABC" مخزنة في المكدس. إذا لم يكن الأمر كذلك ، فقم بتخزين "ABC" على المكدس واترك Str يشير إلى "ABC". إذا كان هناك بالفعل "ABC" ، فدع Str يشير مباشرة إلى "ABC".
عند مقارنة ما إذا كانت القيم في الفصل متساوية ، استخدم طريقة متساوية () ؛ عند اختبار ما إذا كانت مراجع فئتي التفاف تشير إلى نفس الكائن ، استخدم == ، واستخدم المثال أدناه لتوضيح النظرية أعلاه.
String Str1 = "ABC" ؛ String Str2 = "ABC" ؛ system.out.println (str1 == str2) ؛ //حقيقي
يمكن ملاحظة أن Str1 و Str2 يشيران إلى نفس الكائن.
String str1 = سلسلة جديدة ("ABC") ؛ String Str2 = سلسلة جديدة ("ABC") ؛ system.out.println (str1 == str2) ؛ // خطأ شنيع الطريقة الجديدة هي إنشاء كائنات مختلفة. توليد واحدة في وقت واحد.
لذلك ، بالطريقة الثانية ، يتم إنشاء سلاسل "ABC" المتعددة ، وهناك كائن واحد فقط في الذاكرة. طريقة الكتابة هذه مفيدة وتوفر مساحة الذاكرة. في الوقت نفسه ، يمكن أن يحسن سرعة تشغيل البرنامج إلى حد ما ، لأن JVM ستقرر تلقائيًا ما إذا كان من الضروري إنشاء كائن جديد بناءً على الموقف الفعلي للبيانات في المكدس. بالنسبة إلى رمز السلسلة STR = سلسلة جديدة ("ABC") ؛ ، يتم إنشاء كائنات جديدة في الكومة بغض النظر عما إذا كانت قيم السلسلة متساوية أم لا ، ما إذا كان من الضروري إنشاء كائنات جديدة ، وبالتالي زيادة العبء على البرنامج.
من ناحية أخرى ، ملاحظة: عندما نحدد فئة باستخدام تنسيق مثل String STR = "ABC" ؛ ، نأخذ دائمًا أمرا مفروغًا منه أننا ننشئ كائنًا من فئة السلسلة. (ليس بالضرورة ، لأنه إذا لم يكن هناك مقدما ، فسيتم إنشاؤه. هذا هو إنشاء الكائن. إذا كان هناك بالفعل ، ثم أشر إلى الكائن الأصلي)! قد لا يكون الكائن قد تم إنشاؤه! وربما فقط أشير إلى كائن تم إنشاؤه سابقًا. فقط من خلال الطريقة الجديدة () يمكننا التأكد من إنشاء كائن جديد في كل مرة. نظرًا للطبيعة غير القابلة للتغيير لفئة السلسلة ، عندما يحتاج متغير السلسلة إلى تحويل قيمته بشكل متكرر ، يجب عليك التفكير في استخدام فئة StringBuffer لتحسين كفاءة البرنامج.