[英]How do you properly set up a thread to be GC'd in Java?
我想知道如何設置創建的線程以進行GC處理。 我制作了一個簡單的多線程服務器來接受來自客戶端的連接,但是每次客戶端連接時,內存使用量都會增加約80k ...這是可以理解的。 問題是,在客戶端和服務器斷開連接后,我不知道如何從快速增長中退縮。
這是設置線程的主要類:
public static void main(String[] args) {
try {
serverSock= new ServerSocket(9999);
} catch (IOException e1) {
e1.printStackTrace();
}
while (true){
try {
Thread t = new server(serverSock.accept());
t.start();
t = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
這是基本的服務器線程:
public class server extends Thread {
private Socket serverSocket = null;
public static String command = null;
public server(Socket serverSocket2) {
super("server");
serverSocket = serverSocket2;
}
@Override
public void run(){
BufferedReader fromClient = null;
PrintStream toClient = null;
String line = null;
String[] user = new String[2];
try {
serverSocket.setSoTimeout(10000);
fromClient = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
toClient = new PrintStream(serverSocket.getOutputStream());
System.out.println("Got connection");
System.out.println("Terminating server");
fromClient.close();
toClient.close();
serverSocket.close()
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
System.out.println("Connection established, but timeout on" +
" message recieve may have occured");
e.printStackTrace();
}
}
現在,我到底如何允許該線程...死掉然后消失,而不是導致當前發生的內存泄漏?
另外,我是Java的新手-不用介意使用線程,因此,如果很明顯,請嘗試對其進行改進。 感謝您的任何幫助,您可以提供!
GC僅在需要時運行,它似乎並不需要,因此可以清除的對象/線程不需要。 這並不意味着內存泄漏。 這意味着不需要內存。
順便說一句:您不應該直接擴展線程。 相反,我建議您使用Executors.newCachedThreadPool()。 這將更有效地處理短期線程。
同樣,當ServerSocket引發異常時,這是不可恢復的。 這確實意味着一旦失敗,它將無休止地失敗。 如果拋出異常,則將其繼續打印就好像沒有發生那樣,通常是一個壞主意。
不會連續失敗的主版本的較短版本是
public static void main(String... args) throws IOException {
ServerSocket serverSock = new ServerSocket(9999);
ExecutorService es = Executors.newCachedThreadPool();
while (true)
es.submit(new ClientHandler(serverSock.accept()));
}
}
class ClientHandler implements Runnable {
private final Socket socket;
public ClientHandler(Socket socket) { this.socket = socket; }
public void run() {
while(true) {
// do something with the socket.
}
}
}
您怎么知道內存泄漏? 看來我沒有泄漏
您什么都不需要做。 垃圾收集器始終在運行,並且不會[區分]從線程引用的對象與否。
我唯一看到的是, serverSock.accept()
在那里阻塞? 如果沒有,那么您將僅以循環運行時的速度創建線程。 我不是這里的專家,因此,如果在啟動線程之前將accept調用阻塞在那里,則可以這樣做。
在這兩個答案之間,我沒有看到此信息。 GC將清除不活動的線程,因此,如果讓線程退出run()方法,它將被GC清除。 如果沒有其他活動線程從該線程的堆棧中引用該內存,或者沒有靜態根引用該線程,則從該線程的堆棧引用的所有內存都將被清除(Falmarri的回答第2點對此有錯誤,或者至少措辭錯誤)。 GC通常是免提的,並且自動運行,在正常情況下,您實際上不需要多少工作來釋放內存。
現在,創建線程時看到的內存有所不同。 您如何測量80K跳? 您是否正在使用任務管理器,top或某些OS工具來查看這種情況? 操作系統工具對真正了解JVM內部發生的情況並沒有太大幫助。 可能正在釋放OS工具看不到的JVM內部的內存。 原因是Java的內存分配很st。 一旦分配了更多內存,即使不使用它也會保留它。 原因是因為OS將內存分配給進程的速度很慢。 如果以后再保留它,並且統計數據說是肯定的,則通過保留它,然后保留它而不是釋放它會更快。 如果OS的內存不足或使用的內存很少,則Java將返還內存。 不過,這種情況很少。 Java的內存分配非常有效。
如果您想觀看內存或了解更多詳細信息,建議您使用JVM附帶的jconsole。 它將向您顯示JVM的內部結構,因此您可以看到總的內存,堆和構成堆的4個空間(eden,survivor,tenured,Perm Generation)。 您還可以在Code Gen空間中查看代碼占用了多少內存。 您甚至可以看到活動線程在進程中運行,因此,如果線程被卡住,也可以在那里進行診斷。 您可以選擇請求GC,以便查看應用程序如何使用內存。
這樣做的全部目的是,如果您認為有泄漏,則可以使用此工具開始理解它。 它非常簡單,真正有用,而且免費。 如果您有泄漏,則可能需要像jprofiler這樣的內存分析器來告訴您更多詳細信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.