25000スレッドを割り当ててから解放する小さなアプリケーションがあります。 スレッドが解放されている間、アプリケーションのメモリ消費量は増加し、すべてのスレッドが終了した後も高く保たれます。 スレッドを解放するときにJavaがヒープからメモリをリークする
トップ
は次のようになります。 -heap jmapのは、このようになりますPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9133 root 20 0 22.601g 8.612g 12080 S 0.0 9.1 1:18.61 java
ながら:
Attaching to process ID 9133, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.66-b17
using thread-local object allocation.
Parallel GC with 18 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 100
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 104857600 (100.0MB)
MaxNewSize = 104857600 (100.0MB)
OldSize = 968884224 (924.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 1073741824 (1024.0MB)
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 78643200 (75.0MB)
used = 1572864 (1.5MB)
free = 77070336 (73.5MB)
2.0% used
From Space:
capacity = 13107200 (12.5MB)
used = 0 (0.0MB)
free = 13107200 (12.5MB)
0.0% used
To Space:
capacity = 13107200 (12.5MB)
used = 0 (0.0MB)
free = 13107200 (12.5MB)
0.0% used
PS Old Generation
capacity = 968884224 (924.0MB)
used = 1264416 (1.205841064453125MB)
free = 967619808 (922.7941589355469MB)
0.13050227970271916% used
808 interned Strings occupying 54648 bytes.
私の知る限り見ることができるように、jmapはレポートには何も存在しないことトップで報告された8.612gを説明することができます。
Javaのバージョンは、Oracle 1.8.0_66
あるアプリケーションは、Red Hat Enterprise Linuxサーバー上で実行されます(マイポを)7.1をリリース。
アプリケーションのコードは以下の通りです:
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class WaitTest {
static AtomicInteger ai = new AtomicInteger(0);
public static void main(String[] args) {
List<WaitingThread> threads = new LinkedList<>();
while (true) {
System.out.println("number of threads: " + ai.get());
String s = System.console().readLine();
if (s == null)
System.exit(0);
s = s.trim();
if (s.isEmpty())
continue;
char command = s.charAt(0);
if (command != '+' && command != '-') {
System.out.println("+ or - please");
continue;
}
String num = s.substring(1);
int iNum;
try {
iNum = Integer.parseInt(num.trim());
} catch (Exception ex) {
System.out.println("valid number please");
continue;
}
if (command == '+') {
for (int i = 0; i < iNum; i++) {
WaitingThread t = new WaitingThread();
t.start();
threads.add(t);
}
}
if (command == '-') {
Set<WaitingThread> threadsToJoin = new HashSet<>();
for (Iterator<WaitingThread> it = threads.iterator(); it.hasNext();) {
if (iNum > 0) {
WaitingThread t = it.next();
threadsToJoin.add(t);
synchronized (t.lock) {
t.lock.notify();
}
it.remove();
iNum--;
} else
break;
}
for (WaitingThread t : threadsToJoin)
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.gc();
}
}
static class WaitingThread extends Thread {
public final Object lock = new Object();
@Override
public void run() {
ai.incrementAndGet();
try {
deepStack(200);
} catch (InterruptedException ex) {
} catch (Exception ex) {
System.out.println("exception in thread " + Thread.currentThread().getName() + ", " + ex.getMessage());
} finally {
ai.decrementAndGet();
}
}
private void deepStack(int depth) throws InterruptedException {
if (depth == 0) {
synchronized (lock) {
lock.wait();
}
} else
deepStack(depth - 1);
}
}
}
Here is a link to pmap output:
Here is a link to jmap -dump (hprof)
あなたは、プロセスのヒープ・ダンプをadquireしなければならない –
後に出力をのpmap PID' 'から。 http://man7.org/linux/manage/man1/pmap.1.html –
あなたのスレッドへのすべての参照をthreadsToJoinに保持しているのを見てください。スレッドが完了してもメモリに残ります... – nafas