2009-07-02 25 views
55

Gần đây tôi đã tìm thấy một lỗi gây ra một NullPointerException. Ngoại lệ bị bắt và ghi lại bằng cách sử dụng câu lệnh slf4j tiêu chuẩn. Mã tóm lược bên dưới:NullPointerException ngăn xếp theo dõi không có sẵn mà không có đại lý gỡ lỗi

for(Action action : actions.getActions()) { 
    try { 
     context = action.execute(context); 
    } catch (Exception e) { 
     logger.error("...", e); 
     break; 
    } 
} 

Như bạn thấy, không có gì lạ mắt. Tuy nhiên, trong tất cả các câu lệnh khai báo ngoại lệ mà chúng ta có, chỉ một câu lệnh không in dấu vết ngăn xếp. Tất cả nó in là thông báo (được biểu diễn là "...") và tên của lớp ngoại lệ (java.lang.NullPointerException).

Vì dấu vết ngăn xếp trên một ngoại lệ được tải xuống, tôi nghĩ có thể có sự cố sắp xếp lại lệnh của một số loại và quyết định gọi e.getStackTrace() trước câu lệnh nhật ký. Điều này không có sự khác biệt.

Vì vậy, tôi đã quyết định khởi động lại với tác nhân gỡ lỗi được bật. Tuy nhiên, bởi vì tôi thậm chí gắn liền với quá trình này, tôi nhận thấy rằng bây giờ các dấu vết ngăn xếp được in ấn. Vì vậy, rõ ràng sự hiện diện của các đại lý gỡ lỗi gây ra một số thông tin gỡ lỗi bổ sung để trở nên có sẵn.

Từ đó, tôi đã khắc phục nguyên nhân gốc của ngoại lệ. Nhưng tôi muốn tìm hiểu lý do tại sao ngăn xếp ngăn xếp không có sẵn mà không có trình gỡ lỗi. Có ai biết không?

Làm rõ: đây không phải là sự cố đăng nhập. Hãy tưởng tượng mệnh đề cùng try/catch, nhưng trong đánh bắt, tôi in giá trị của:

e.getStackTrace().length 

Nếu không có một trình gỡ lỗi này in '0', với một trình gỡ lỗi nó in một số dương (9 trong trường hợp này).

Thông tin thêm: điều này xảy ra trên JDK 1.6.0_13, 64bit, amd64, Linux 2.6.9

+2

bạn đang sử dụng vm nào? hành vi đó âm thanh * rất kỳ lạ. –

+0

JDK 1.6.0_13, 64 bit trên Linux 2.6.9 – omerkudat

+0

Điều gì xảy ra khi bạn 'ném NullPointerException()' mới vào trong thử? – seth

Trả lời

18

Có thể rằng mã này là trong một vòng lặp bên trong? Sau đó, trình biên dịch JIT có thể biên dịch ngăn xếp cuộc gọi cho mã này thành mã gốc, mất thông tin ngăn xếp. Sau đó, khi bạn đính kèm trình gỡ rối nó vô hiệu hóa JIT, làm cho thông tin có sẵn trở lại.

Ngoại lệ thủ công khác tiếp tục hiển thị thông tin khi JIT không tối ưu hóa.

Nó trông như thế này đôi khi có thể xảy ra cho những người khác từ một lời nhận xét trong mã nguồn của lớp này tại dòng 102:

http://logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.html

+3

Sau đó, tôi quản lý để xác nhận rằng việc tắt JIT (JAVA_COMPILER = false) làm cho toàn bộ dấu vết ngăn xếp khả dụng bất cứ khi nào ngoại lệ này xảy ra. – omerkudat

0

tôi có thể tái tạo này nhưng có vẻ như loại lạ rằng điều này sẽ xảy ra trong hành động của bạn ở đâu đó.

Nếu bạn gọi setStackTrace với một mảng trống, điều đó sẽ chỉ làm cho văn bản được hiển thị.

public class Fark { 
    public static void main(String[] args) { 
     try { 
      Fark.throwMe(args.length != 0); 

     } 
     catch (Exception e) { 
      e.printStackTrace(); 
     } 

    } 

    public static final void throwMe(boolean arg) throws Exception{ 
     Exception e = new NullPointerException(); 
     if (arg) { 
      e.setStackTrace(new StackTraceElement[0]); 
     } 
     throw e; 
    } 
} 

Chạy nó ....

% java Fark 
java.lang.NullPointerException 
     at Fark.throwMe(Fark.java:15) 
     at Fark.main(Fark.java:5) 

% java Fark nothing 
java.lang.NullPointerException 
+0

Có, ai đó cũng đã đề cập đến điều này. Đây không phải là trường hợp. – omerkudat

+0

Liệu điều tương tự có xảy ra nếu bạn chỉ cần ném một NullPointerException mình trong thử? – seth

+0

Có, cùng một hành vi nếu tôi tự ném bằng tay. Và điều này chỉ xảy ra trong thử/nắm bắt này. Ở những nơi khác mà tôi ném theo cách thủ công, tôi nhận được hành vi bình thường (nghĩa là, toàn bộ stack). – omerkudat

83

Với XX JVM cờ: -OmitStackTraceInFastThrow bạn có thể vô hiệu hóa việc tối ưu hóa hiệu suất của JVM cho trường hợp sử dụng này. Nếu tham số này được cho, sẽ vô hiệu hóa cờ, stacktrace sẽ có sẵn.

Để biết thêm thông tin xin vui lòng có một cái nhìn tại các ghi chú phát hành sau:

"Trình biên dịch trong máy chủ ảo hiện nay cung cấp đống vết lùi đúng cho tất cả 'lạnh' built-in ngoại lệ Đối với mục đích hoạt động, khi đó một. Sau khi biên dịch lại, trình biên dịch có thể chọn một chiến thuật nhanh hơn bằng cách sử dụng các ngoại lệ preallocated mà không cung cấp một dấu vết ngăn xếp để vô hiệu hóa hoàn toàn việc sử dụng các ngoại lệ preallocated, sử dụng cờ mới này: -XX : -OmitStackTraceInFastThrow. " http://java.sun.com/j2se/1.5.0/relnotes.html

+0

Điều này rất thú vị, cảm ơn bạn đã chỉ ra. – omerkudat

+3

Chúng tôi đã gặp vấn đề tương tự một lần nữa và đã thử tùy chọn này, và nó hoạt động thực sự tốt, tốt hơn nhiều so với việc tắt hoàn toàn JIT. Cảm ơn! – omerkudat

+0

Cảm ơn bạn đã chỉ ra điều này! – Daniel

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