简体   繁体   English

插入USB热点后,简单的Java程序慢了100倍

[英]Simple Java program 100 times slower after plugging in USB hotspot

I have following Java program: 我有以下Java程序:

class Main {
    public static void main(String[] args) throws java.io.IOException {
        long start = System.nanoTime();
        java.io.File.createTempFile("java_test", ".txt").delete();
        System.out.println((System.nanoTime() - start ) / 1e9);
    }
}

Normally, it takes bout 63 miliseconds to execute: 通常,执行需要大约63毫秒:

$ java Main
0.06308555

But, once I connect Android phone as USB hotspot, it takes significantly longer. 但是,一旦我将Android手机作为USB热点连接,它需要更长的时间。 Depending on the machine anywhere from 3 to 40 seconds: 根据机器的不同,从3到40秒:

$ java Main
4.263285528

The strange thing is that nothing here is actually transferred over the network - plugged network adapters shouldn't matter. 奇怪的是,这里没有任何东西实际通过网络传输 - 插入的网络适配器应该无关紧要。

I did a backtrace and it looks like majority of time is spent in NetworkInterface.getAll method: 我做了一个回溯,看起来大部分时间花在NetworkInterface.getAll方法上:

"main" #1 prio=5 os_prio=0 tid=0x00000000023ae000 nid=0x142c runnable [0x000000000268d000]
   java.lang.Thread.State: RUNNABLE
        at java.net.NetworkInterface.getAll(Native Method)
        at java.net.NetworkInterface.getNetworkInterfaces(Unknown Source)
        at sun.security.provider.SeedGenerator.addNetworkAdapterInfo(Unknown Source)
        at sun.security.provider.SeedGenerator.access$000(Unknown Source)
        at sun.security.provider.SeedGenerator$1.run(Unknown Source)
        at sun.security.provider.SeedGenerator$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.security.provider.SeedGenerator.getSystemEntropy(Unknown Source)
        at sun.security.provider.SecureRandom$SeederHolder.<clinit>(Unknown Source)
        at sun.security.provider.SecureRandom.engineNextBytes(Unknown Source)
        - locked <0x000000076afa2820> (a sun.security.provider.SecureRandom)
        at java.security.SecureRandom.nextBytes(Unknown Source)
        - locked <0x000000076af6bdc8> (a java.security.SecureRandom)
        at java.security.SecureRandom.next(Unknown Source)
        at java.util.Random.nextLong(Unknown Source)
        at java.io.File$TempDirectory.generateFile(Unknown Source)
        at java.io.File.createTempFile(Unknown Source)
        at java.io.File.createTempFile(Unknown Source)
        at Main.main(Main.java:4)

which, in turn, seems to spend most of the time in GetIfTable Windows API method: 反过来,它似乎大部分时间都GetIfTable Windows API方法中:

Child-SP          RetAddr           Call Site
00000000`0257ed78 000007fe`fd7210ba ntdll!NtDeviceIoControlFile+0xa
00000000`0257ed80 000007fe`fd721252 nsi+0x10ba
00000000`0257ee20 000007fe`fd7211f9 nsi!NsiEnumerateObjectsAllParametersEx+0x2e
00000000`0257ee60 000007fe`fd7217b0 nsi!NsiEnumerateObjectsAllParameters+0xc9
00000000`0257ef00 000007fe`f9c7928d nsi!NsiAllocateAndGetTable+0x184
00000000`0257efd0 00000000`6f8c5a01 IPHLPAPI!GetIfTable+0xa9
00000000`0257f090 00000000`6f8c6980 net!Java_java_net_NetworkInterface_getMTU0+0x1a1
00000000`0257f150 00000000`6f8c6e57 net!Java_java_net_NetworkInterface_isP2P0_XP+0x88
00000000`0257f270 00000000`6f8c6058 net!Java_java_net_NetworkInterface_getAll_XP+0x23
00000000`0257f2a0 00000000`02867f54 net!Java_java_net_NetworkInterface_getAll+0x2c

GetIfTable seems to be the problematic function. GetIfTable似乎是有问题的功能。 I'm observing the same slowdown both in example program from: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx and with following snippet: 我在以下示例程序中观察到同样的减速: https//msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v = vs.85).aspx以及以下代码段:

#include <iphlpapi.h>
#include <stdlib.h>

int main() {
    DWORD dwSize = sizeof(MIB_IFTABLE);
    MIB_IFTABLE *pIfTable = malloc(dwSize);
    GetIfTable(pIfTable, &dwSize, FALSE);
    pIfTable = malloc(dwSize);
    GetIfTable(pIfTable, &dwSize, FALSE);
    return 0;
}

How do I fix or workaround this problem? 如何修复或解决此问题? I can create temporary files on my own and avoid calling NetworkInterface.getNetworkInterfaces but SecureRandom is used all over Java standard library. 我可以自己创建临时文件,避免调用NetworkInterface.getNetworkInterfaces,但SecureRandom遍布Java标准库。 Is there a way to force SecureRandom not to use GetIfTable? 有没有办法强制SecureRandom不使用GetIfTable?

Java version: Java版本:

> java -version
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

Windows version: Windows版本:

OS Name:                   Microsoft Windows 7 Professional
OS Version:                6.1.7601 Service Pack 1 Build 7601

Problematic network adapter: 有问题的网络适配器:

Name    [00000020] Remote NDIS based Internet Sharing Device
Adapter Type    Ethernet 802.3
Product Type    Remote NDIS based Internet Sharing Device
Installed   Yes
PNP Device ID   USB\VID_0FCE&PID_71C4&MI_00\7&6BE3F3B&0&0000
Last Reset  8/14/2016 12:26 PM
Index   20
Service Name    usb_rndisx
IP Address  192.168.42.183, fe80::90ab:3786:4396:2870
IP Subnet   255.255.255.0, 64
Default IP Gateway  192.168.42.129
DHCP Enabled    Yes
DHCP Server 192.168.42.129
DHCP Lease Expires  8/14/2016 3:27 PM
DHCP Lease Obtained 8/14/2016 2:27 PM
MAC Address 02:18:61:77:7D:72
Driver  c:\windows\system32\drivers\usb8023x.sys (6.1.7600.16385, 19.50 KB (19,968 bytes), 7/14/2009 2:09 AM)

Default implementation of SecureRandom scans network interfaces as an additional source of system entropy. SecureRandom默认实现扫描网络接口作为系统熵的额外来源。 In order to avoid this, you need to register a custom java.security.Provider that contains a different implementation of SecureRandomSpi . 为了避免这种情况,您需要注册包含SecureRandomSpi的不同实现的自定义java.security.Provider

Fortunately, JDK for Windows already has a suitable SecureRandomSpi implementation that relies on Microsoft Crypto API: sun.security.mscapi.PRNG . 幸运的是,JDK for Windows已经有一个合适的SecureRandomSpi实现,它依赖于Microsoft Crypto API: sun.security.mscapi.PRNG Though this is non-public API, the class exists in all versions of OpenJDK and Oracle JDK from 1.6 to 9, and the fallback is available anyway. 虽然这是非公共API,但是该类在所有版本的OpenJDK和Oracle JDK中都存在1.6到9,并且无论如何都可以使用后备版。

There are two ways to register MS Crypto PRNG as the default SecureRandom algorithm. 有两种方法可以将MS Crypto PRNG注册为默认的SecureRandom算法。

1. From within the application by calling WindowsSecureRandom.register() at the very beginning. 1.从应用程序内部开始调用WindowsSecureRandom.register()

import java.security.Provider;
import java.security.Security;

public class WindowsSecureRandom extends Provider {
    private static final String MSCAPI = "sun.security.mscapi.PRNG";

    private WindowsSecureRandom() {
        super("WindowsSecureRandom Provider", 1.0, null);
        putService(new Service(this, "SecureRandom", "Windows-PRNG", MSCAPI, null, null));
    }

    public static void register() {
        if (System.getProperty("os.name").contains("Windows")) {
            try {
                Class.forName(MSCAPI);
                Security.insertProviderAt(new WindowsSecureRandom(), 1);
            } catch (ClassNotFoundException e) {
                // Fallback to default implementation
            }
        }
    }
}

2. By reordering provider list in %JAVA_HOME%\\jre\\lib\\security\\java.security file. 2.通过重新排序%JAVA_HOME%\\jre\\lib\\security\\java.security文件中的提供程序列表。

security.provider.1=sun.security.mscapi.SunMSCAPI  <<<--- make it the first provider
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
...

I've verified that with either solutions SeedGenerator and NetworkInterface classes are no longer loaded. 我已经验证,无论是哪种解决方案,都不再加载SeedGeneratorNetworkInterface类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM