Java 생성자 및 정적 초기화기의 65,535 바이트 한계를 초과하는 이유는 무엇입니까?

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

  •  16-09-2019
  •  | 
  •  

문제

면책 조항 : Java에서 런타임에 이것을 생성 할 수 있다는 것을 알고 있습니다. 이것은 일부 코드를 테스트하는 동안 매우 특별한 경우에 필요했습니다. 나는 다른 접근법을 발견 했으므로 이제 이것은 실용적인 것보다 호기심이 더 많습니다.

나는 다음을 인스턴스 필드로 정적 필드로 시도하고 생성자 내에서 직접 초기화했습니다. Eclipse가 "생성자 TestData ()의 코드가 65535 바이트 제한을 초과하는 것"또는 "정적 이니셜 라이저의 코드가 65535 바이트 제한을 초과하는 것"을 알려줍니다.

10,000 정수가 있습니다. 각 int가 4 바이트 (32bits) 인 경우 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
도움이 되었습니까?

해결책

다음은 {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 바이트가됩니다. 따라서 100000 요소의 경우 약 80kb의 바이트 코드를 기대해야합니다.

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 정수가 취한 메모리가 아닙니다.

나는 이것이 ints를 영숫자로 표현하는 데 필요한 메모리의 양일 가능성이 있다고 생각합니다. 이 한계는 코드 자체에 적용될 수 있다고 생각합니다. 예를 들어 각 INT는 다음과 같습니다. 1494512072는 실제로 int32에 사용되는 4 바이트 대신 실제로 10 바이트 (숫자 당 하나)를 사용합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top