2016-08-19 74 views
0

執行低級別X11編程時,通常需要在返回的結構上調用XFree()。例如XGetWMName,我在下面的代碼,然後與JNA X11和XFree

AssertionMessage: *** Error in `/opt/jdk1.8.0_40/bin/java': double free or corruption (fasttop): 0x00007f7ca822bdd0 *** 

這是由XFree的()調用導致幾秒鐘後炸燬做到了這一點,如果被去除的問題消失。但是監測與頂級工藝穩定顯示內存增長暗示我需要它...

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平臺相關的例子。

+1

XLib不會爲您分配'XTextProperty'。你用'new X11.XTextProperty()'分配一個。因此你不應該'XFree'它。 –

回答

0

總之,內存幕後管理當JNA Java對象被垃圾回收時,JNA會被com.sun.jna.Memory.finalize()自動釋放給你。

/** Properly dispose of native memory when this object is GC'd. */ 
protected void finalize() { 
    dispose(); 
} 

/** Free the native memory and set peer to zero */ 
protected synchronized void dispose() { 
    free(peer); 
    peer = 0; 
    allocatedMemory.remove(this); 
} 

你不應該叫XFree的(),如果你這樣做,你在原來的問題"double free or corruption (fasttop)"詳細的風險「雙解除」的錯誤。

這意味着當您使用JNA實現時,讀取X11函數的手冊頁會讓您感到困惑。這些手冊頁通常指導您使用XFree清理返回的資源。

1

您想釋放XTextProperty結構的value字段中的指針,而不是結構本身。

XTextProperty man page

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.value); 
+0

謝謝你的回答,請你能提供一個代碼示例嗎?注意這是JNA綁定到X11上的,所以簽名是XFree(com.sun.jna.Pointer),所以看不到x11.XFree(name.getPointer())以外的任何東西)。 – Adam