2009-06-03 33 views
18

Vấn đề: Tôi có một phương thức biên dịch đến hơn 8000 byte bytecode Java. HotSpot có giới hạn phép thuật khiến JIT không khởi động các phương thức vượt quá 8000 byte. (Có, nó là hợp lý để có một phương pháp rất lớn. Đây là một vòng lặp tokenizer.) Phương thức này nằm trong thư viện và tôi không muốn yêu cầu người dùng thư viện phải cấu hình HotSpot để hủy kích hoạt giới hạn ma thuật.Có trình tối ưu hóa bytecode Java nào xóa các ảnh không sử dụng được không?

Quan sát: Việc giải mã mã byte cho thấy Trình biên dịch Java của Eclipse tạo ra rất nhiều hình ảnh vô nghĩa. (javac thậm chí còn tồi tệ hơn.) Đó là, có những gotos mà chỉ có thể truy cập từ nhảy. Rõ ràng, nhảy nhảy đến goto thay vào đó nên nhảy trực tiếp nơi nhảy goto và goto nên được loại bỏ.

Câu hỏi: Có trình tối ưu hóa bytecode cho các tệp lớp Java 5 làm phẳng chuỗi nhảy vô nghĩa và sau đó loại bỏ các ảnh không cần thiết?

Edit: Tôi có nghĩa là các mẫu như:

8698: goto 8548 
8701: goto 0 

Rõ ràng, goto thứ hai chỉ có thể đạt được bởi một bước nhảy đến 8701 mà cũng có thể là một bước nhảy trực tiếp đến 0.

Trên một thứ hai điều tra, mẫu đáng ngờ này là phổ biến hơn:

4257: if_icmpne 4263 
4260: goto 8704 
4263: aload_0 

đâu rõ ràng, người ta muốn trình biên dịch để đảo ngược "không bình đẳng" so với "bình đẳng" so sánh, nhảy đến 870 4 và loại bỏ các goto.

+3

Một số kiến ​​trúc có giới hạn về mức độ tương đối của nhánh tương đối (vì chúng giữ địa chỉ trong thanh ghi 8 hoặc 16 bit) nên chúng thường đi xung quanh đó với nhánh tương đối đến chi nhánh không liên quan đã sử dụng đầy đủ kích thước bộ đếm chương trình. Là JVM như thế? –

+0

Bạn có nghĩa là * LABELS * chỉ có thể truy cập từ các bước nhảy không? –

+0

Một chú thích thời gian chạy để đưa ra một gợi ý cho JVM chắc chắn sẽ tốt đẹp trong trường hợp này .... nhưng tôi không nghĩ rằng một điều như vậy tồn tại (và một google nhanh chóng không bật lên bất cứ điều gì.) – Jared

Trả lời

0

Một phương pháp biên dịch đến hơn 8000 byte? Có ai hiểu mã đó không? Là có thể kiểm chứng? Cố gắng chia nó thành nhiều (riêng tư?) Phương pháp với tên có ý nghĩa thay vì phức tạp với trình tối ưu hóa!

OK, có thể có những trường hợp phương pháp hợp pháp lớn. Nhưng xin lỗi, không có gợi ý nào trong câu hỏi.

+1

Nghe có vẻ như anh ta đang viết một trình phân tích cú pháp - nó thực sự rất hợp lý cho một vòng lặp tokenizer để có được lớn, và nó thực sự * nhiều hơn * có thể đọc được để giữ nó lại với nhau. (Tôi đã có folks buộc tôi phá vỡ một phương pháp như vậy chỉ vì nó đã được trên n dòng và tháng tiếp theo họ phàn nàn vì nó là khó khăn hơn để làm theo ...) –

+2

Vâng, tôi hiểu được mã. Nó cũng bản đồ chặt chẽ hơn với spec hơn bất kỳ cải cách nào như các phương pháp gốc đệ quy. Có, nó có thể kiểm tra với một tập lớn các bài kiểm tra đơn vị. – hsivonen

1

Tôi cảm thấy đau đớn của bạn. Tôi đã phải viết một phân tích cú pháp khi đã có khoảng 5kloc nếu (str.equals (...)) mã. Tôi đã chia thành nhiều phương pháp dọc theo các dòng của parse1, parse2, v.v. Nếu parse1 không dẫn đến câu trả lời được phân tích cú pháp, parse2 được gọi, v.v. Đây không nhất thiết phải là thực hành tốt nhất, nhưng nó thực hiện những gì bạn cần .

+1

btw: trong trường hợp bạn không biết, bạn đã triển khai mẫu "Chain of Responsibility" với cách tiếp cận parse1, parse2 etc (không phải đó là điều xấu hay tốt cho vấn đề này), chỉ muốn đề cập đến nó. ..) –

+0

Tôi từng có nhiều phương thức thay vì một công tắc lớn trong một vòng lặp. Tuy nhiên, cấu trúc chuyển đổi lớn phù hợp với thông số kỹ thuật tốt hơn và nhanh hơn khi JIT khởi động. – hsivonen

+0

Bạn luôn có thể thực hiện chuyển đổi nhỏ hơn() và trường hợp mặc định gọi phương thức khác bằng công tắc nhỏ và cứ như vậy cho đến khi tất cả trường hợp chuyển đổi được bảo hiểm. Điều này sẽ không được tốt đẹp như một bảng chuyển đổi lớn, nhưng nó sẽ làm việc. Trong trường hợp của tôi, tôi không thể sử dụng switch vì nó không hoạt động trên Strings. – KitsuneYMG

0

Nó có tạo sự khác biệt nếu bạn không biên dịch với các biểu tượng gỡ lỗi (tức là cờ -g trong javac) không? Điều đó có thể đưa phương pháp xuống dưới giới hạn ma thuật.

+0

Ít nhất trong Trình biên dịch Java Eclipse, điều này không ảnh hưởng đến số lượng bytecode trong phương thức được biên dịch. (Tôi cho rằng bảng gỡ lỗi là riêng biệt.) – hsivonen

0

Có thể không thể tái cấu trúc phương pháp thành các phép đo con? JIT hiện đại của nội tuyến những cuộc gọi anyway.

+2

nếu trước đây bạn chưa viết một trình phân tích cú pháp, đôi khi máy quét (lexer/tokenizer) có thể lớn, nhưng khả năng đọc có thể giảm xuống khi bạn chia nhỏ. tất nhiên tôi chưa thấy mã của anh ấy, nhưng tôi đã ở đó ... –

+0

Tôi đã chia các hành động tokenizer thực tế có thể được tách ra mà không ảnh hưởng đến luồng điều khiển. Cấu trúc điều khiển chính nó là rất lớn. – hsivonen

+1

@scott, trước đây tôi đã viết một trình phân tích cú pháp. Nếu nó quá phức tạp (vì bất kỳ lý do cụ thể nào) thì đây có thể là thời điểm hợp lý để xem xét một trình tạo trình phân tích cú pháp phù hợp. –

0

Nếu đó là một vòng lặp tokenizer, nó sẽ là tốt hơn để làm điều đó với một tập dữ liệu drivapped của ánh xạ và một chút phản ánh khi thích hợp?

Vì vậy, bạn sẽ lưu trữ các đối sánh mã thông báo của mình trong cấu trúc ánh xạ chúng tới dữ liệu về cú pháp của mã thông báo đó và các phương pháp triển khai các hàm được liên kết. Tra cứu có thể được tối ưu hóa trên cấu trúc và bạn tránh vòng lặp lớn.

Điều đó giới thiệu vấn đề giữ dữ liệu và triển khai đồng bộ, nhưng bạn có thể tạo dữ liệu từ cơ sở mã của bạn bằng doclet hoặc có thể là chú thích.

Không biết chính xác phương pháp lớn của bạn làm gì, chúng tôi bị giới hạn cố gắng tối ưu hóa nó theo cách bạn cho là tốt nhất (và điều này dường như không thể).

+0

Không, lý tưởng là bạn muốn chuyển đổi trạng thái để biên dịch xuống để nhảy vào mã — không phải tra cứu cấu trúc dữ liệu. – hsivonen

+0

Chắc chắn điều đó phụ thuộc vào việc bạn có thể tối ưu hóa tra cứu - cả thông qua tìm kiếm hiệu quả không gian phù hợp và thông qua bộ nhớ đệm của kết quả. Một chuỗi mã thông báo lớn, cứng được mã hóa có thể khá khả năng tối ưu hóa (mà tôi đoán là lý do tại sao bạn đang tìm kiếm trợ giúp JIT). Trong một dự án trước, tôi đã sử dụng tham chiếu phương thức được lưu trong bộ nhớ cache với kết quả khá tốt. Các thay đổi trong 'nguồn' chỉ cần thiết để vô hiệu hóa tham chiếu để thực hiện tra cứu mới và thực thi bình thường có thể chạy ở tốc độ tốt, kích hoạt các cuộc gọi phương thức mà không có bất kỳ hiệu suất nào từ khớp mã thông báo. – AndyT

0

hiệu suất của bạn có tăng lên không nếu bạn chạy bộ thu nhỏ/mã vạch trên lớp của bạn? ví dụ: yguard, proguard, ...

có thể bạn có thể viết một trình xử lý tệp lớp bằng cách sử dụng asm vì trường hợp sử dụng của bạn quá cụ thể.

ngay cả khi bạn xóa tất cả các hình ảnh vô nghĩa, điều đó có mang lại cho bạn dưới giới hạn phép thuật không?

0

Danh sách bytecode libraries đề cập đến BCELASM, mà tôi đã nghe nói về trước đây, cùng với nhiều người khác đang làm nhiều việc khác nhau.

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