Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
奇怪现象:Java/Swing操作导致本机库(JNA)中的访问冲突_Java_Swing_Access Violation_Jna - Fatal编程技术网

奇怪现象:Java/Swing操作导致本机库(JNA)中的访问冲突

奇怪现象:Java/Swing操作导致本机库(JNA)中的访问冲突,java,swing,access-violation,jna,Java,Swing,Access Violation,Jna,各位开发者好 因为SO几乎总是对我的编程问题有帮助,所以我决定注册,并尝试解决我最近的问题。这真是一个奇怪的现象,我和我的同事都无法理解。很抱歉,我不能提供一个工作样本,但该项目是复杂的方式来分解它,并需要特定的硬件来正常运行它。所以我会尽力解释的 我们项目的基础是本地库(在这种情况下是32位Windows C-DLL),它通过java应用程序()访问特定于项目的硬件。其目的是在Swing UI中管理和显示硬件的专有文件系统(通过USB连接)。这对我们来说是一种非常常见的项目配置,因为我们在Ja

各位开发者好

因为SO几乎总是对我的编程问题有帮助,所以我决定注册,并尝试解决我最近的问题。这真是一个奇怪的现象,我和我的同事都无法理解。很抱歉,我不能提供一个工作样本,但该项目是复杂的方式来分解它,并需要特定的硬件来正常运行它。所以我会尽力解释的

我们项目的基础是本地库(在这种情况下是32位Windows C-DLL),它通过java应用程序()访问特定于项目的硬件。其目的是在Swing UI中管理和显示硬件的专有文件系统(通过USB连接)。这对我们来说是一种非常常见的项目配置,因为我们在Java应用程序中集成了许多本机库和驱动程序

摘要:用于枚举设备的单元测试工作正常。本机库的一个模块分配内存并用结构填充内存,每个结构都包含所连接设备的信息。这不是一个好的做法,但既然我们对这一部分没有任何影响,我们就必须这样做。我在Java/JNA中映射了这个结构,调用本机函数,将结构内容复制到Java传输类,并在控制台中打印它。很好用

现在,如果枚举设备时有UI操作处于活动状态,则本机库会因访问冲突而崩溃。即使此UI操作与库无关。JNA错误消息显示异常访问冲突(0xc0000005),因此研究显示为无效/空内存

以前有人遇到过这样的问题吗?我们当然从来没有这样做过。我花了好几天时间才把错误源缩小到代码的这一部分。当涉及本机库时,调试并不容易。 是否可能存在JVM内存并发问题?由于本机库自己分配内存,而JVM对此一无所知,所以JVM会尝试在已经使用的内存中为新的Swing组件分配内存

代码: 下面的代码片段来自我的单元测试,尽可能地细分。预期的顺序很明显:从根节点删除节点,加载连接的设备,并将这些设备添加为新节点。这段代码会因访问冲突而崩溃,但不会在本机调用时崩溃——只要我访问树组件,它就会崩溃

    public void loadDevices(){
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                rootNode.removeAllChildren();
                rootNode.add(new LoadingNode());
                tree.expandPath(new TreePath(rootNode));
            }
        });

        final List<Device> devices = lib.loadDevices(); // wrapped native call

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                rootNode.removeAllChildren();
                if(!devices.isEmpty()){
                    for (Device dev : devices ) {
                        DevNode node = new DevNode(dev);
                        rootNode.add(node);
                    }
                }
            }
         });
     }
public void loadDevices(){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
rootNode.removeAllChildren();
添加(新加载节点());
expandPath(新树路径(根节点));
}
});
final List devices=lib.loadDevices();//包装的本机调用
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
rootNode.removeAllChildren();
如果(!devices.isEmpty()){
用于(设备开发:设备){
DevNode节点=新的DevNode(dev);
添加(node);
}
}
}
});
}
注意:DevNode不包含任何本机数据,每个本机结构的内容都复制到Java传输对象。GC在尝试移动对象数据时不应该出现问题,因为所有非托管代码都是在lib#loadDevices()方法中本地处理的

当我完全删除对SwingUtilities的调用并将生成的设备信息打印到控制台而不是创建节点时,这部分工作正常。 一旦我试图访问JTree或TreeModel成员,代码就会崩溃。如果我在调用swingutilies#invokeLater()或在同一个线程中执行此操作,则不起作用

我知道这是一个非常具体的问题,几乎没有人会感兴趣(是什么使得在SO/Google中搜索解决方案变得非常困难)。但也许我很幸运,有人已经遇到了这个问题

再见
桑德

编辑:最初,此代码被包装在工作线程中,导致相同的结果。这只是我的单元测试的一个片段

编辑2:我好像说得不够清楚,或者忘了在这里提到一些重要的事情,对不起。对树或其模型的访问不一定与本机库有关。再看一遍代码:对invokeLater的第一次调用只会从树中删除节点。即使我删除了对invokeLater的第二个调用,本机库也会崩溃

final List devices=lib.loadDevices();
final List<Device> devices = lib.loadDevices();
  • (假设使用JNA的代码能够单独返回每个节点,或者在结束时一次返回
    列表的
    集合)应该从工作线程调用,例如Runnable#Thread或SwingWorker

  • 直接(或通过创建新的MutableTreeNode)添加到DefaultTreeModel的to工作线程的所有输出都应包装到invokeLater中

  • 如果不发布(
    列表的
    可能是USB端口列表),短的、可运行的、可编译的,大约是JTree,是模型,JNI/JNA


在我学会这一点之前,我与JTree进行了很多艰苦的斗争:

在JTree上,不应编辑节点本身,而应使用DefaultTreeModel上提供的方法:

setRoot(TreeNode root) 
removeNodeFromParent(MutableTreeNode node) 
insertNodeInto(MutableTreeNode newChild, MutableTreeNode parent, int index) 
编辑节点本身可能(并且迟早会)导致奇怪的行为


当您使用DefaultTreeModel和MutableTreeNode时,当然会出现这种情况。我强烈建议您这样做,因为我已经看到许多错误的TreeModel实现。

您是否有机会将侦听器连接到
JTree
/
TreeModel
,从而触发本机代码?感谢您的快速响应!不,是这样