47 votes

Simple programme Java 100 fois plus lent après l'avoir branché en USB hotspot

J'ai suite à un programme en 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);
    }
}

Normalement, il faut bout 63 milisecondes à exécuter:

$ java Main
0.06308555

Mais, une fois que j'ai connecter le téléphone Android USB hotspot, il prend beaucoup plus de temps. Selon la machine n'importe où de 3 à 40 secondes:

$ java Main
4.263285528

La chose étrange est que rien ici n'est effectivement transférées sur le réseau branché cartes réseau ne compte pas.

J'ai fait une trace et il semble que la majorité du temps est passé en NetworkInterface.getAll méthode:

"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)

qui, à son tour, semble passer la plupart du temps, en GetIfTable méthode de l'API Windows:

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 semble être la problématique de la fonction. Je suis en observant le même ralentissement à la fois dans le programme d'exemple de: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs. 85).aspx et avec l'extrait de code suivant:

#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;
}

Comment puis-je corriger ou contourner ce problème? Je peux créer des fichiers temporaires sur moi-même et éviter d'appeler NetworkInterface.getNetworkInterfaces mais SecureRandom est utilisé partout en Java de la bibliothèque standard. Est-il un moyen de forcer SecureRandom de ne pas utiliser GetIfTable?

Version de 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)

Version Windows:

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

Problématique de la carte réseau:

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)

36voto

apangin Points 4693

L'implémentation par défaut de SecureRandom scans interfaces réseau comme une source supplémentaire de l'entropie du système. Afin d'éviter cela, vous devez vous inscrire à une coutume java.security.Provider qui contient une mise en œuvre différente de SecureRandomSpi.

Heureusement, JDK pour Windows a déjà adapté SecureRandomSpi mise en œuvre qui s'appuie sur l'API Crypto de Microsoft: sun.security.mscapi.PRNG. Si c'est non-API publique, la classe existe dans toutes les versions de OpenJDK et Oracle JDK de 1,6 à 9, et la solution de repli est à disposition de toute façon.

Il y a deux façons de s'inscrire MS Crypto PRNG que le défaut SecureRandom algorithme.

1. Au sein de l'application en appelant WindowsSecureRandom.register() dès le début.

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. Par la réorganisation de la liste des fournisseurs en %JAVA_HOME%\jre\lib\security\java.security le fichier.

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
...

J'ai vérifié que soit avec les solutions d' SeedGenerator et NetworkInterface les classes ne sont plus chargées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X