Почему это превышает ограничение в 65 535 байт в конструкторах Java и статических инициализаторах?

StackOverflow https://stackoverflow.com/questions/788787

  •  16-09-2019
  •  | 
  •  

Вопрос

Отказ от ответственности:Я понимаю, что могу сгенерировать это во время выполнения на Java, это было необходимо для очень особого случая при тестировании производительности некоторого кода.Я нашел другой подход, так что теперь это скорее любопытство, чем что-либо практическое.

Я попробовал следующее в качестве статического поля, в качестве поля экземпляра и инициализировал непосредственно в конструкторе.Каждый раз eclipse сообщает мне, что либо "Код конструктора TestData() превышает ограничение в 65535 байт", либо "Код статического инициализатора превышает ограничение в 65535 байт".

Существует 10 000 целых чисел.Если каждый int равен 4 байтам (32 битам), то разве это не будет 40 000 байт?Действительно ли существует больше, чем 25,0000 байт накладных расходов в дополнение к данным, просто создающим массив?

Данные генерируются с помощью этого небольшого фрагмента python:

#!/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
Это было полезно?

Решение

Вот байт-код для инициализации массива с помощью {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 байт байт-кода Java.Для вашего большего массива как индекс массива, так и индекс в пуле констант будут использовать 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top