Java JNA 4.3.0 在查找进程时产生大量垃圾
Java JNA 4.3.0 Creates Insane Amout of Garbage When Looking for Process
当我试图通过名称查找虚假进程时,JNA 产生了大量垃圾。
这是分配的屏幕截图(大约 100k.sec)
这里是测试用例(使用JNA的4.3.0 SNAPSHOT)
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
/**
* Created by Jonathan on 8/26/2016.
*/
public class Main {
public static void main(String[] args) {
while (true)
openProcess("doesntexist.exe");
}
private static final WinDef.DWORD DWORD_ZERO = new WinDef.DWORD(0);
private static final Tlhelp32.PROCESSENTRY32 entry = new Tlhelp32.PROCESSENTRY32.ByReference();
private static WinNT.HANDLE openProcess(String processName) {
WinNT.HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPALL, DWORD_ZERO);
try {
while (Kernel32.INSTANCE.Process32Next(snapshot, entry)) {
String fileName = Native.toString(entry.szExeFile);
if (processName.equals(fileName))
return Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_ALL_ACCESS, true, entry.th32ProcessID.intValue());
}
} finally {
Kernel32.INSTANCE.CloseHandle(snapshot);
}
return null;
}
}
最后是内存快照
https://dl.dropboxusercontent.com/u/91292881/ShareX/2016/08/JNA%204.3.0.snapshot
我强烈怀疑你的堆使用是在你的循环中重复创建新的 String
对象。
您的代码在另一个无限循环中执行进程搜索(遍历每个进程),因此您有效地一遍又一遍地执行这一行...
String fileName = Native.toString(entry.szExeFile);
在内部,Native.toString(char[] buf)
每次都创建一个 new String()
:
public static String toString(char[] buf) {
int len = buf.length;
for (int index = 0; index < len; index++) {
if (buf[index] == '[=11=]') {
len = index;
break;
}
}
if (len == 0) {
return "";
} else {
return new String(buf, 0, len);
}
}
这些String
对象被用于测试相等性一次,然后被扔到堆上。
由于创建 String
的主要目的是测试相等性,您可以直接使用底层 char[]
数组来测试相等性。将 processName
转换为 char[]
并同时遍历两个数组,测试字符相等性直至 processName
的长度,并在 entry.szExeFile
的下一个字符中使用空终止符。
当我试图通过名称查找虚假进程时,JNA 产生了大量垃圾。
这是分配的屏幕截图(大约 100k.sec)
这里是测试用例(使用JNA的4.3.0 SNAPSHOT)
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
/**
* Created by Jonathan on 8/26/2016.
*/
public class Main {
public static void main(String[] args) {
while (true)
openProcess("doesntexist.exe");
}
private static final WinDef.DWORD DWORD_ZERO = new WinDef.DWORD(0);
private static final Tlhelp32.PROCESSENTRY32 entry = new Tlhelp32.PROCESSENTRY32.ByReference();
private static WinNT.HANDLE openProcess(String processName) {
WinNT.HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPALL, DWORD_ZERO);
try {
while (Kernel32.INSTANCE.Process32Next(snapshot, entry)) {
String fileName = Native.toString(entry.szExeFile);
if (processName.equals(fileName))
return Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_ALL_ACCESS, true, entry.th32ProcessID.intValue());
}
} finally {
Kernel32.INSTANCE.CloseHandle(snapshot);
}
return null;
}
}
最后是内存快照 https://dl.dropboxusercontent.com/u/91292881/ShareX/2016/08/JNA%204.3.0.snapshot
我强烈怀疑你的堆使用是在你的循环中重复创建新的 String
对象。
您的代码在另一个无限循环中执行进程搜索(遍历每个进程),因此您有效地一遍又一遍地执行这一行...
String fileName = Native.toString(entry.szExeFile);
在内部,Native.toString(char[] buf)
每次都创建一个 new String()
:
public static String toString(char[] buf) {
int len = buf.length;
for (int index = 0; index < len; index++) {
if (buf[index] == '[=11=]') {
len = index;
break;
}
}
if (len == 0) {
return "";
} else {
return new String(buf, 0, len);
}
}
这些String
对象被用于测试相等性一次,然后被扔到堆上。
由于创建 String
的主要目的是测试相等性,您可以直接使用底层 char[]
数组来测试相等性。将 processName
转换为 char[]
并同时遍历两个数组,测试字符相等性直至 processName
的长度,并在 entry.szExeFile
的下一个字符中使用空终止符。