web-dev-qa-db-ja.com

シンプルJava USBホットスポットを接続した後、プログラムが100倍遅くなる

私は次の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);
    }
}

通常、実行には約63ミリ秒かかります。

$ Java Main
0.06308555

しかし、Android電話をUSBホットスポットとして接続すると、かなり時間がかかります。マシンによっては、3〜40秒かかります。

$ Java Main
4.263285528

奇妙なことに、ここでは実際にはネットワークを介して何も転送されません。接続されたネットワークアダプタは問題ではありません。

バックトレースを実行しましたが、時間の大部分が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)

これは、ほとんどの時間をGetIfTable WindowsAPIメソッドに費やしているようです。

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は問題のある関数のようです。次のサンプルプログラムの両方で同じ速度低下が見られます: 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;
}

この問題を修正または回避するにはどうすればよいですか?自分で一時ファイルを作成してNetworkInterface.getNetworkInterfacesを呼び出さないようにすることはできますが、SecureRandomはJava標準ライブラリ全体で使用されます。SecureRandomにGetIfTableを使用しないように強制する方法はありますか?

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版:

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

問題のあるネットワークアダプタ:

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)
47
Piotr Praszmo

システムエントロピーの追加ソースとしてのSecureRandomネットワークインターフェイスをスキャン のデフォルトの実装。これを回避するには、 SecureRandomSpi の異なる実装を含むカスタム _Java.security.Provider_ を登録する必要があります。

幸い、JDK for Windowsには、Microsoft CryptoAPIに依存する適切なSecureRandomSpi実装がすでにあります: _Sun.security.mscapi.PRNG_ 。これは非公開APIですが、クラスは1.6から9までのOpenJDKおよびOracle JDKのすべてのバージョンに存在し、フォールバックはとにかく利用できます。

MS Crypto PRNGをデフォルトのSecureRandomアルゴリズムとして登録する方法は2つあります。

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。_%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
...
_

どちらのソリューションでも、SeedGeneratorクラスとNetworkInterfaceクラスがロードされていないことを確認しました。

34
apangin