Tôi đang gửi Callable
đối tượng vào một số ThreadPoolExecutor
và dường như chúng được gắn bó trong bộ nhớ.Làm thế nào để đảm bảo thu gom rác của FutureTask được gửi đến ThreadPoolExecutor và sau đó bị hủy?
Nhìn vào đống đổ với công cụ MAT cho Eclipse thấy rằng các đối tượng Callable
đang được tham chiếu bởi một callable biến FutureTask$Sync
's. Điều đó FutureTask$Sync
được tham chiếu bởi một biến số đồng bộ của FutureTask
. Điều đó FutureTask
được tham chiếu bởi số của FutureTask$Sync
này $ 0.
Tôi đã đọc xung quanh về vấn đề này (here, here, và trên SO) và nó có vẻ như FutureTask
rằng callable được gói trong khi ThreadPoolExecutor
's nộp() giữ một tham chiếu đến callable mãi mãi.
Điều tôi đang bối rối là làm thế nào để đảm bảo rằng FutureTask
bị thu gom rác để nó không tiếp tục giữ được bộ nhớ trong bộ nhớ, và giữ bất cứ thứ gì có thể gọi được trong bộ nhớ?
Chỉ để cung cấp thêm chi tiết về tình huống cụ thể của tôi, tôi đang cố gắng triển khai ThreadPoolExecutor
theo cách cho phép tất cả các tác vụ đã gửi bị hủy nếu cần. Tôi đã thử một số phương pháp khác nhau mà tôi tìm thấy trên SO và các nơi khác, chẳng hạn như tắt hoàn toàn trình điều hành (với shutdown()
, shutdownNow()
v.v.) và cũng giữ danh sách tương lai quay lại submit()
và hủy cuộc gọi trên tất cả chúng rồi xóa danh sách tương lai. Lý tưởng nhất là tôi không muốn phải tắt nó, và chỉ cancel()
và rõ ràng khi cần thiết.
Tất cả các phương pháp này dường như không tạo nên sự khác biệt. Nếu tôi gửi một cuộc gọi đến các hồ bơi, có một cơ hội tốt nó sẽ kết thúc gắn bó xung quanh.
Tôi đang làm gì sai?
Cảm ơn.
Edit:
Theo yêu cầu, ở đây là các nhà xây dựng cho ThreadPoolExecutor.
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
Sau khi kiểm tra thêm, tôi có thể thấy rằng nếu tôi để các tác vụ đã được gửi đến ThreadPoolExecutor kết thúc, thì không có rò rỉ.Nếu tôi cố gắng hủy chúng trong anyway như:
shutdownNow()
Hoặc tiết kiệm một tham chiếu đến tương lai và kêu gọi hủy bỏ vào nó sau:
Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);
Hoặc bằng cách loại bỏ chúng ra khỏi hàng đợi với các phương pháp như:
getQueue.drainTo(someList)
hoặc
getQueue.clear()
hoặc Looping thông qua tài liệu tham khảo lưu vào tương lai và gọi:
getQueue.remove(task)
Bất kỳ của những trường hợp gây ra FutureTask để dính vào xung quanh như đã mô tả ở trên. Vì vậy, câu hỏi thực sự trong tất cả những điều này là làm thế nào để tôi đúng cách hủy bỏ hoặc loại bỏ các mặt hàng từ một ThreadPoolExecutor để các FutureTask là rác thu thập và không bị rò rỉ mãi mãi?
đăng mã của bạn, theo cách khó loại bỏ: 'ThreadPoolExecutor.getQueue(). Remove (future)' sẽ thực hiện thủ thuật – bestsss
Có một số thảo luận về việc liệu getQueue() có nên được sử dụng theo cách đó hay không. Có thực sự là một nhược điểm để làm theo cách đó? – cottonBallPaws
@bestsss Tôi đã hy vọng tôi sẽ không nhận được yêu cầu đó;) Mã có rất nhiều đang xảy ra và tôi không chắc chắn những phần có liên quan đến vấn đề này. Tôi đã hy vọng để có được một ý thức chung về những gì có thể gây ra một rò rỉ liên quan đến FutureTask. Có một phần cụ thể mà bạn muốn xem không? – cottonBallPaws