JNA X11 和 XFree
JNA X11 and XFree
进行低级 X11 编程时,通常需要对返回的结构调用 XFree()。例如 XGetWMName,我在下面的代码中完成了这个,然后在几秒钟后用
爆炸了
AssertionMessage: *** Error in `/opt/jdk1.8.0_40/bin/java': double free or corruption (fasttop): 0x00007f7ca822bdd0 ***
这是由 XFree() 调用引起的,如果删除它,问题就会消失。但是用 top 监控进程显示稳定的内存增长表明我确实需要它...
public class X11WindowFinder {
private X11 x11;
public X11WindowFinder() {
x11 = X11.INSTANCE;
}
public List<Window> find(Pattern title) {
Display display = x11.XOpenDisplay(null);
Window root = x11.XDefaultRootWindow(display);
List<Window> windows = recurse(x11, display, root, title);
x11.XCloseDisplay(display);
return windows;
}
private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
List<Window> windows = new ArrayList<>(1);
X11.WindowByReference windowRef = new X11.WindowByReference();
X11.WindowByReference parentRef = new X11.WindowByReference();
PointerByReference childrenRef = new PointerByReference();
IntByReference childCountRef = new IntByReference();
x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
if (childrenRef.getValue() == null) {
return Collections.emptyList();
}
long[] ids = {};
if (Native.LONG_SIZE == Long.BYTES) {
ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
} else if (Native.LONG_SIZE == Integer.BYTES) {
int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
ids = new long[intIds.length];
for (int i = 0; i < intIds.length; i++) {
ids[i] = intIds[i];
}
}
for (long id : ids) {
Window child = new Window(id);
X11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
String value = name.value;
if (value != null) {
System.out.println(String.format("Found window %s free %s", value, name));
}
if (value != null && pattern.matcher(value).matches()) {
windows.add(child);
}
x11.XFree(name.getPointer());
windows.addAll(recurse(x11, display, child, pattern));
}
return windows;
}
public static void main(String[] args) {
X11WindowFinder finder = new X11WindowFinder();
while (true) {
finder.find(Pattern.compile(".*Firefox.*"));
}
}
}
JNA 中的指针似乎使用 finalize() 来释放内存,即 com.sun.jna.Memory.finalize()
/** Properly dispose of native memory when this object is GC'd. */
protected void finalize() {
dispose();
}
因此,如果我调用 XFree(),我冒着被双重释放的风险...这个假设是否正确。我能找到几个 JNA 的例子,尤其是 X11 平台相关的。
您想释放 XTextProperty
结构的 value
字段中的指针,而不是结构本身。
To free the storage for the value field, use XFree.
根据您的代码(请注意 value
字段应该是 Pointer
而不是 String
):
x11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
// ... do some stuff
x11.XFree(name.getPointer());
编辑
请注意,根据 XTextProperty
的当前定义,value
字段映射到 Java String
,这有效地隐藏了原始指针。您需要使用 XTextProperty.getPointer(XXX)
(其中 XXX 是 value
字段的偏移量)才能访问要传递给 XFree
的原始指针值。由于 value
字段在结构中排在第一位,因此使用 Structure
本身的基地址也可以工作(即 Structure.getPointer()
)。
对 XFree
的调用实际上应该是 XTextProperty
自己的内存清理(终结器)的一部分。
进行低级 X11 编程时,通常需要对返回的结构调用 XFree()。例如 XGetWMName,我在下面的代码中完成了这个,然后在几秒钟后用
爆炸了AssertionMessage: *** Error in `/opt/jdk1.8.0_40/bin/java': double free or corruption (fasttop): 0x00007f7ca822bdd0 ***
这是由 XFree() 调用引起的,如果删除它,问题就会消失。但是用 top 监控进程显示稳定的内存增长表明我确实需要它...
public class X11WindowFinder {
private X11 x11;
public X11WindowFinder() {
x11 = X11.INSTANCE;
}
public List<Window> find(Pattern title) {
Display display = x11.XOpenDisplay(null);
Window root = x11.XDefaultRootWindow(display);
List<Window> windows = recurse(x11, display, root, title);
x11.XCloseDisplay(display);
return windows;
}
private synchronized List<Window> recurse(X11 x11, Display display, Window root, Pattern pattern) {
List<Window> windows = new ArrayList<>(1);
X11.WindowByReference windowRef = new X11.WindowByReference();
X11.WindowByReference parentRef = new X11.WindowByReference();
PointerByReference childrenRef = new PointerByReference();
IntByReference childCountRef = new IntByReference();
x11.XQueryTree(display, root, windowRef, parentRef, childrenRef, childCountRef);
if (childrenRef.getValue() == null) {
return Collections.emptyList();
}
long[] ids = {};
if (Native.LONG_SIZE == Long.BYTES) {
ids = childrenRef.getValue().getLongArray(0, childCountRef.getValue());
} else if (Native.LONG_SIZE == Integer.BYTES) {
int[] intIds = childrenRef.getValue().getIntArray(0, childCountRef.getValue());
ids = new long[intIds.length];
for (int i = 0; i < intIds.length; i++) {
ids[i] = intIds[i];
}
}
for (long id : ids) {
Window child = new Window(id);
X11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
String value = name.value;
if (value != null) {
System.out.println(String.format("Found window %s free %s", value, name));
}
if (value != null && pattern.matcher(value).matches()) {
windows.add(child);
}
x11.XFree(name.getPointer());
windows.addAll(recurse(x11, display, child, pattern));
}
return windows;
}
public static void main(String[] args) {
X11WindowFinder finder = new X11WindowFinder();
while (true) {
finder.find(Pattern.compile(".*Firefox.*"));
}
}
}
JNA 中的指针似乎使用 finalize() 来释放内存,即 com.sun.jna.Memory.finalize()
/** Properly dispose of native memory when this object is GC'd. */
protected void finalize() {
dispose();
}
因此,如果我调用 XFree(),我冒着被双重释放的风险...这个假设是否正确。我能找到几个 JNA 的例子,尤其是 X11 平台相关的。
您想释放 XTextProperty
结构的 value
字段中的指针,而不是结构本身。
To free the storage for the value field, use XFree.
根据您的代码(请注意 value
字段应该是 Pointer
而不是 String
):
x11.XTextProperty name = new X11.XTextProperty();
x11.XGetWMName(display, child, name);
// ... do some stuff
x11.XFree(name.getPointer());
编辑
请注意,根据 XTextProperty
的当前定义,value
字段映射到 Java String
,这有效地隐藏了原始指针。您需要使用 XTextProperty.getPointer(XXX)
(其中 XXX 是 value
字段的偏移量)才能访问要传递给 XFree
的原始指针值。由于 value
字段在结构中排在第一位,因此使用 Structure
本身的基地址也可以工作(即 Structure.getPointer()
)。
对 XFree
的调用实际上应该是 XTextProperty
自己的内存清理(终结器)的一部分。