2012-10-08 22 views
5

tôi quan sát thấy trong NetBeans Profiler rằng Surviving Generations vẫn tiếp tục tăng sau khi tôi thực hiện truy vấn:rò rỉ bộ nhớ MyBatis trong một truy vấn mà kết quả là một danh sách các avg. 30k hàng

@Select("SELECT * FROM ais_dynamic WHERE rep_time >= #{from} AND rep_time <= #{to} AND ais_system = #{sys}")  
@Options(useCache=false,fetchSize=8192) 
List<AisDynamic> getRecords(
     @Param("from") Timestamp from, 
     @Param("to") Timestamp to, 
     @Param("sys") int sys); 

Nó là như nếu đối tượng nằm trong danh sách không bao giờ được phát hành mặc dù họ không được sử dụng bất cứ nơi nào khác và phải chết với chuỗi nền chạy truy vấn và xử lý kết quả của nó.

Dưới đây là kết quả trực tiếp trả về bởi NetBeans Profiler: Live results from NetBeans Profiler

Câu hỏi của tôi:

  1. Làm thế nào tôi có thể ngăn chặn sự rò rỉ bộ nhớ?
  2. Làm cách nào để tối ưu hóa truy vấn này, vì có thể thấy tôi bắt đầu chơi với Options mặc dù điều này không ngăn chặn rò rỉ bộ nhớ?

Nếu cần gì, vui lòng cho tôi biết tôi sẽ cung cấp những gì.

UPDATE:

Sau khi kiểm tra tôi càng quan tâm nhiều hơn là vấn đề đặt với MyBatis giữ một tham chiếu đến các kết quả lấy ra như vậy, họ không phải là thu gom rác thải theo thời gian. Sau khi thực hiện 20 cuộc gọi của truy vấn thì chờ đợi tôi quan sát không có bộ sưu tập rác ngay cả sau 30 phút. Tất cả những gì tôi làm là gọi phương thức: List<AisDynamic> adList = mapper.getRecords(from, to, sys);

+0

Tôi cũng bị rò rỉ bộ nhớ với MyBatis. Bạn có tìm thấy giải pháp nào cho vấn đề của mình không? – Marc

+0

@Marc Tôi quan sát thấy rằng nó chỉ xảy ra cho các tình huống khi tôi lấy một số lượng lớn các hàng lớn hơn 10k. Các giải pháp mà làm việc cho tôi là sử dụng một JDBC và mã tất cả bằng tay tất cả cùng nhau và vấn đề đã biến mất. Đã kiểm tra ngay cả đối với 50 nghìn hàng. Mặc dù nó đã giải quyết được vấn đề cho tôi nhưng tôi thực sự thích dùng MyBatis hơn vì nó tiết kiệm rất nhiều mã hóa nhưng trong trường hợp này, điều đó là không thể. Mặc dù tôi đang chờ đợi một giải pháp tốt hơn, ai biết được có thể sửa chữa API là cần thiết? – Boro

+0

Bạn có thể thêm cấu hình này vào tệp cấu hình MyBatis của bạn và xem có sự khác biệt nào không: '' – partlov

Trả lời

3

Tôi đã thử nghiệm nó vào cuối tuần và có vẻ như tôi đã giải quyết được sự cố. Cảm ơn @partlov vì đề xuất này, mặc dù nó không phải là giải pháp mà nó giúp tôi kiểm tra lại vấn đề và tôi đã phát hiện ra vấn đề thực sự.

Vấn đề là khách hàng của tôi chịu trách nhiệm xử lý các yêu cầu truy vấn từ người dùng đã chồng chất các chủ đề (đang thực hiện truy vấn). Vì các yêu cầu đã đến rất thường xuyên khi tôi nhấn mạnh thử nghiệm máy khách nên khi truy vấn trước đó không được thực hiện, lệnh tiếp theo sẽ bắt đầu ngay cả khi tôi đã hủy chúng bằng cách cài đặt và kiểm tra cờ trong phương thức truy vấn run(). Điều này xuất hiện trong các tình huống khi phiên truy vấn vẫn đang nói chuyện với cơ sở dữ liệu, ví dụ: khi một lựa chọn có kết quả 30k +. Vì vậy, mặc dù cờ hủy bỏ được nâng lên, nó vẫn chưa được kiểm tra vì truy vấn đang trong quá trình truy xuất kết quả từ cơ sở dữ liệu. Đây là đủ thời gian cho các truy vấn tiếp theo để bắt đầu vì vậy nếu nó cũng có nhiều kết quả khách hàng đã chồng chất lên các chủ đề có hiệu lực tiêu thụ nhiều hơn và nhiều hơn nữa bộ nhớ.

Vì dường như không có cách nào (mà tôi biết) để hủy phiên (ví dụ: truy vấn chọn) nói chuyện với cơ sở dữ liệu (trong MyBatis), tôi phải thực hiện một cơ chế bảo vệ khỏi chính nó. Cơ chế mà tôi đã triển khai trong ứng dụng khách của tôi đảm bảo rằng truy vấn tiếp theo sẽ không bắt đầu cho đến khi truy vấn trước đó (được thực hiện cho cùng một người dùng) được hoàn tất. Do đó, bây giờ một truy vấn thông báo cho máy khách khi nó thoát khỏi phương thức run() của nó và chỉ khi đó truy vấn tiếp theo cho cùng một người dùng có thể được bắt đầu.


Cập nhật tôi học được từ kinh nghiệm rằng chỉ và là một cách bẩn bit (mỗi hương vị của tôi) để hủy bỏ/hủy bỏ một giao dịch nhặt đồ dài là bằng cách gọi close() phương pháp của SqlSession dụ rằng giao dịch sử dụng.Điều này sẽ dẫn đến một ngoại lệ (ví dụ dưới đây) mà phải được bắt và xử lý như dự định.

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database. Cause: java.lang.NullPointerException 
### The error may exist in YourMapper.java (best guess) 
### The error may involve methodOfTheHandlerInvolved 
### The error occurred while handling results 
### SQL: sqlOfYourQuery 
### Cause: java.lang.NullPointerException 
... (and a trace follows) ...