لماذا يتجاوز هذا الحد 65،535 البايت في منشئين Java والتهفية الثابتة؟
سؤال
إخلاء المسئولية: أدرك أنني أستطيع توليد هذا في وقت التشغيل في جافا، وكان هناك حاجة إلى حالة خاصة للغاية أثناء اختبار الأداء بعض التعليمات البرمجية. لقد وجدت نهجا مختلفا، لذلك الآن هذا مجرد فضول أكثر من أي شيء عملي.
لقد جربت ما يلي كحقل ثابت، كحقل مثيل، وتهيئة مباشرة داخل المنشئ. في كل مرة تقوم فيها الكسوف بإبلاغني بأن "رمز البناء TestData () يتجاوز حدود البايتات 65535" أو "رمز التهيئة الثابت يتجاوز حد البايت 65535".
هناك 10000 صحيحة. إذا كانت كل int هي 4 بايت (32 مليار)، فهل لن يكون 40،000 بايت؟ هل هناك حقا أكثر من 25،0000 بايت من النفقات العامة بالإضافة إلى البيانات فقط بناء صفيف؟
يتم إنشاء البيانات مع هذا القليل صغير من الثعبان:
#!/usr/bin/python
import random;
print "public final int[] RANDOM_INTEGERS = new int[] {";
for i in range(1,10000):
print str(int(random.uniform(0,0x7fffffff))) + ",";
print "};";
إليك عينة صغيرة:
public final int[] RANDOM_INTEGERS = new int[] {
963056418, 460816633, 1426956928, 1836901854, 334443802, 721185237, 488810483,
1734703787, 1858674527, 112552804, 1467830977, 1533524842, 1140643114, 1452361499,
716999590, 652029167, 1448309605, 1111915190, 1032718128, 1194366355, 112834025,
419247979, 944166634, 205228045, 1920916263, 1102820742, 1504720637, 757008315,
67604636, 1686232265, 597601176, 1090143513, 205960256, 1611222388, 1997832237,
1429883982, 1693885243, 1987916675, 159802771, 1092244159, 1224816153, 1675311441,
1873372604, 1787757434, 1347615328, 1868311855, 1401477617, 508641277, 1352501377,
1442984254, 1468392589, 1059757519, 1898445041, 1368044543, 513517087, 99625132,
1291863875, 654253390, 169170318, 2117466849, 1711924068, 564675178, 208741732,
1095240821, 1993892374, 87422510, 1651783681, 1536657700, 1039420228, 674134447,
1083424612, 2137469237, 1294104182, 964677542, 1506442822, 1521039575, 64073383,
929517073, 206993014, 466196357, 1139633501, 1692533218, 1934476545, 2066226407,
550646675, 624977767, 1494512072, 1230119126, 1956454185, 1321128794, 2099617717,
//.... to 10,0000 instances
المحلول
هنا هو bytecode لتهيئة صفيف مع {1000001، 1000002، 1000003}:
5 iconst_3
6 newarray int [10]
8 dup
9 iconst_0
10 ldc <Integer 1000001> [12]
12 iastore
13 dup
14 iconst_1
15 ldc <Integer 1000002> [13]
17 iastore
18 dup
19 iconst_2
20 ldc <Integer 1000003> [14]
22 iastore
23 putfield net.jstuber.test.TestArrayInitializingConstructor.data : int[] [15]
لذلك بالنسبة إلى هذه الصفيف الصغيرة يتطلب كل عنصر 5 بايت من جافا bytecode. بالنسبة لمجموعك الأكبر، سيستخدم مؤشر الصفيف والفهرس في المسبح الثابت 3 بايت لمعظم العناصر، مما يؤدي إلى 8 بايت لكل عنصر صفيف. لذلك بالنسبة إلى 10000 عنصر يتعين عليك توقعه حوالي 80 كيلو بايت من الكود البايت.
يبدو رمز تهيئة صفائف كبيرة مع مؤشرات 16 بت مثل هذا:
2016 dup
2017 sipush 298
2020 ldc_w <Integer 100298> [310]
2023 iastore
2024 dup
2025 sipush 299
2028 ldc_w <Integer 100299> [311]
نصائح أخرى
يتم ترجمة حرف مجموعة الصفيف إلى رمز البايت الذي يملأ الصفيف مع القيم، لذلك تحتاج إلى عدد قليل من بايت لكل رقم.
لماذا لا تنقل تلك البيانات إلى مورد تقوم بتحميله في وقت تحميل الفصل في كتلة تهيئة ثابتة؟ يمكن بسهولة القيام بذلك باستخدام MyClass.class.getClassLoader().getResourceAsStream()
. وبعد يبدو أن هذا هو المكان الذي ينتمي إليه، على أي حال.
أو الأفضل من ذلك، إنشاء القيم العشوائية في كتلة التهيئة الثابتة باستخدام أدوات Java المتاحة. وإذا كنت بحاجة إلى أرقام "عشوائية" قابلة للتكرار، ثم فقط البذور Random
مثيل رقم ثابت ولكنه اختيار عشوائيا في كل مرة.
إلى جانب قيم الأعداد الصحيحة، يحتاج المنشئ والتهيئة إلى احتواء تعليمات JVM لتحميل الأعداد الصحيحة في الصفيف.
تتمثل النهج الأكثر بساطة وأكثر عملية في تخزين الأرقام في ملف، إما بتنسيق ثنائي أو كنص.
لا أعرف ما تهما به Java صفائف بهذه الطريقة، لكنها لا تهيئة صففا كبيرة بكفاءة.
أعتقد أن حجم التعليمات البرمجية في الشخصيات هو أكثر من 65535. وليس الذاكرة التي تم التقاطها بواسطة 10000 أعداد صحيحة.
أعتقد أنه من الممكن أن يكون هذا مقدار الذاكرة المطلوبة لتمثيل تلك الأبدية الأبجدية الأبجدية. أعتقد أن هذا الحد قد ينطبق على الكود نفسه، لذلك، كل int، على سبيل المثال: 1494512072 يأخذ فعلا 10 بايت (واحد لكل رقم) بدلا من 4 بايت فقط المستخدمة في INT32.