Warum überschreitet dies die 65.535 Byte -Grenze bei Java -Konstruktoren und statischen Initialisierern?

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

  •  16-09-2019
  •  | 
  •  

Frage

Haftungsausschluss: Mir ist klar, dass ich dies zur Laufzeit in Java generieren kann. Dies wurde für einen ganz besonderen Fall benötigt, während Performance -Code getestet wurde. Ich habe einen anderen Ansatz gefunden, also ist dies jetzt nur eine Neugier als alles andere.

Ich habe das Folgende als statisches Feld als Instanzfeld ausprobiert und direkt innerhalb des Konstruktors initialisiert. Jedes Mal, wenn Eclipse mich mitteilt, dass "der Code von Konstruktor testdata () die 65535 -Bytes -Grenze überschreitet" oder "der Code für den statischen Initialisierer überschreitet die 65535 -Bytes -Grenze".

Es gibt 10.000 Ganzzahlen. Wenn jeder int 4 Bytes (32bit) ist, dann wäre das nicht 40.000 Bytes? Gibt es wirklich mehr als 25.0000 Bytes Overhead zusätzlich zu den Daten, die nur das Array konstruieren?

Die Daten werden mit diesem kleinen Stück Python generiert:

#!/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 "};";

Hier ist ein kleines Beispiel:

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
War es hilfreich?

Lösung

Hier ist der Bytecode zum Initialisieren eines Arrays mit {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]

Für dieses kleine Array benötigt jedes Element 5 Bytes Java -Bytecode. Für Ihr größeres Array verwendet sowohl der Array -Index als auch der Index in den konstanten Pool 3 Bytes für die meisten Elemente, was zu 8 Bytes pro Array -Element führt. Für 10000 Elemente müssen Sie also etwa 80 KB Byte -Code erwarten.

Der Code für die Initialisierung großer Arrays mit 16 -Bit -Indizes sieht so aus:

2016  dup
2017  sipush 298
2020  ldc_w <Integer 100298> [310]
2023  iastore
2024  dup
2025  sipush 299
2028  ldc_w <Integer 100299> [311]

Andere Tipps

Array -Literale werden in den Byte -Code übersetzt, der das Array mit den Werten füllt, sodass Sie für jede Zahl ein paar weitere Bytes benötigen.

Verschieben Sie diese Daten nicht in eine Ressource, die Sie in einem statischen Initialisiererblock in der Klassenladungszeit laden? Dies kann problemlos durch die Verwendung erfolgen MyClass.class.getClassLoader().getResourceAsStream(). Es scheint, dass es sowieso dort hingehört.

Oder erstellen Sie die zufälligen Werte im statischen Initialisiererblock mit den verfügbaren Java -Tools. Und wenn Sie wiederholbare "zufällige" Zahlen benötigen, dann säen Sie einfach die Random Instanz mit einer festen, aber zufällig ausgewählten Zahl jedes Mal.

Neben den Werten der Ganzzahlen muss der Konstruktor und der Initialisierer die JVM -Anweisungen zum Laden der Ganzzahlen in das Array enthalten.

Ein viel einfacherer und praktischerer Ansatz besteht darin, die Zahlen in einer Datei entweder in einem binären Format oder als Text zu speichern.

Ich weiß nicht, was Java auf diese Weise initialisiert, aber es wird große Arrays nicht effizient initialisiert.

Ich denke, dass die Codegröße in Zeichen mehr als 65535 beträgt. Nicht der Speicher von 10000 Ganzzahlen.

Ich denke, es ist möglich, dass dies die Menge an Speicher ist, die erforderlich ist, um diese INTs alphanumerisch darzustellen. Ich denke, diese Grenze kann für den Code selbst gelten. So benötigt jeder int, zum Beispiel: 1494512072 tatsächlich 10 Bytes (eine pro Ziffer) anstelle von nur 4 Bytes, die für den INT32 verwendet werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top