2009-04-25 24 views
9

Tuyên bố từ chối trách nhiệm: Tôi nhận ra rằng tôi có thể tạo điều này khi chạy trong Java, điều này là cần thiết cho một trường hợp rất đặc biệt trong khi kiểm tra hiệu suất một số mã. Tôi đã tìm thấy một cách tiếp cận khác, vì vậy bây giờ đây chỉ là một sự tò mò hơn bất cứ điều gì thực tế.Tại sao điều này vượt quá giới hạn 65.535 byte trong các nhà xây dựng Java và Trình khởi tạo tĩnh?

Tôi đã thử các trường sau đây dưới dạng trường tĩnh, dưới dạng trường mẫu và được khởi tạo trực tiếp trong hàm tạo. Mỗi lần nhật thực thông báo cho tôi rằng "Mã của hàm tạo TestData() vượt quá giới hạn 65535 byte" hoặc "Mã cho trình khởi chạy tĩnh vượt quá giới hạn 65535 byte".

Có 10.000 số nguyên. Nếu mỗi int là 4 byte (32bits), thì đó sẽ không phải là 40.000 byte? Có thực sự nhiều hơn rằng 25,0000 byte của chi phí ngoài các dữ liệu chỉ đơn thuần là xây dựng mảng?

Dữ liệu được tạo ra với chút nhỏ này 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 "};"; 

Dưới đây là một ví dụ nhỏ:

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 
+0

Khi đọc về điều này, tôi thấy rằng giới hạn này áp dụng cho tất cả các phương pháp (bao gồm các hàm tạo) cũng như các trình khởi tạo tĩnh. Hấp dẫn! –

+0

http://groups.google.com/group/comp.lang.java.machine/browse_thread/thread/b0cf268515f1ef55 –

Trả lời

13

Đây là bytecode cho khởi tạo một mảng với {1.000.001, 1.000.002, 1.000.003}:

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] 

Vì vậy, cho mảng nhỏ này mỗi phần tử đòi hỏi 5 byte Java bytecode. Đối với mảng lớn hơn của bạn cả chỉ mục mảng và chỉ mục vào nhóm không đổi sẽ sử dụng 3 byte cho hầu hết các phần tử, dẫn đến 8 byte cho mỗi phần tử mảng. Vì vậy, đối với 10000 yếu tố bạn phải mong đợi khoảng 80kB mã byte.

Mã cho khởi tạo mảng lớn với 16 chỉ số chút trông như thế này:

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

Các chuỗi ký tự được xử lý đặc biệt? Đó có phải là điều duy nhất? Sẽ có ý nghĩa khi khởi tạo mảng bằng cách đóng gói dữ liệu thành chuỗi ký tự [có thể nói, đối với 'int' giá trị, số +/- 16383 lưu trữ dưới dạng một ký tự, +/- 268435455 hoặc một số giá trị chọn khác lưu dưới dạng hai và bất kỳ thứ gì khác như ba]? – supercat

+0

@supercat Vâng, điều đó có thể hiệu quả. Mỗi chuỗi sử dụng hai chỉ số hồ bơi không đổi, một cho chuỗi (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.3) và một cho dữ liệu UTF-8 thực tế (http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.7). Theo như tôi có thể thấy không có loại liên tục nào khác có kích thước tùy ý nào đó (xem 4.4 The Constant Pool http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms- 4.4). Mặc dù tôi muốn sử dụng một tài nguyên hơn là một hack. – starblue

-4

Tôi nghĩ rằng nó có thể rằng đây là dung lượng bộ nhớ cần thiết để đại diện cho những ints chữ và số. Tôi nghĩ rằng giới hạn này có thể áp dụng cho chính mã, vì vậy, mỗi int, ví dụ: 1494512072 thực sự mất 10 byte (một chữ số) thay vì chỉ 4 byte được sử dụng cho int32.

+0

Tôi khá chắc chắn "mã" đang được tham chiếu trong thông báo lỗi đề cập đến bytecode được tạo. –

0

Tôi nghĩ rằng kích thước mã trong ký tự là hơn 65535. Không phải bộ nhớ được thực hiện bởi 10000 số nguyên.

+0

11 ký tự lần 10.000 mục là 110.000 byte, nhiều hơn hoặc ít hơn. Hoàn toàn vượt quá giới hạn –

+1

Tại sao câu trả lời này lại được bình chọn? Đó là chính xác, theo một cách tối giản. –

3

Bên cạnh giá trị của số nguyên, hàm tạo và trình khởi tạo cần chứa hướng dẫn JVM để tải các số nguyên vào mảng.

+0

Vì vậy, tôi đoán đây là những gì tôi đã mong đợi, chỉ cần ngạc nhiên một mã init literal mảng là> 25.000 byte (Tôi chắc chắn có một số chi phí nhỏ trong việc thiết lập các lớp/phương pháp/etc). –

+1

Bạn có thể sử dụng javap để xem những gì đang diễn ra. – TrayMan

6

Mảng chữ được dịch sang mã byte lấp đầy mảng bằng các giá trị, vì vậy bạn cần thêm vài byte cho mỗi số.

Tại sao không di chuyển dữ liệu đó ra thành tài nguyên mà bạn tải vào thời gian tải lớp trong khối khởi tạo tĩnh? Điều này có thể dễ dàng được thực hiện bằng cách sử dụng MyClass.class.getClassLoader().getResourceAsStream(). Dường như đây là nơi nó thuộc về, dù sao đi nữa.

Hoặc tốt hơn, hãy tạo các giá trị ngẫu nhiên trong khối khởi tạo tĩnh bằng cách sử dụng các công cụ Java có sẵn. Và nếu bạn cần các số "ngẫu nhiên" có thể lặp lại, thì chỉ cần nhân giống cá thể Random với số cố định, nhưng được chọn ngẫu nhiên mỗi lần.

+2

Môi trường đang được kiểm tra không cho phép truy cập I/O tệp. –

+2

Nhưng bạn đang tải các lớp, vì vậy bạn có thể làm MyClass.class.getResourceAsStream() và tải nó từ jar bạn đóng gói ứng dụng của bạn. Điều đó sẽ * luôn luôn * có thể. –

1

Một cách tiếp cận đơn giản hơn nhiều và thực tế hơn là để lưu trữ các số trong một tập tin, hoặc trong một định dạng nhị phân hoặc dưới dạng văn bản.

Tôi không biết những gì java khởi tạo mảng theo cách này, nhưng nó không khởi tạo mảng lớn một cách hiệu quả.

Các vấn đề liên quan