A simple Java program is 100 times slower after connecting a USB access point

I have the following Java program:

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

Typically, it takes 62 milliseconds to execute:

 $ java Main 0.06308555 

But, as soon as I connect my Android phone to a USB access point, it takes significantly longer. Depending on the device, from 3 to 40 seconds:

 $ java Main 4.263285528 

The strange thing is that nothing is transmitted over the network here - the connected network adapters should not matter.

I did backtracking and it looks like most of the time is spent in the NetworkInterface.getAll method:

 "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, usually spends most of the time in the GetIfTable method of the 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 a problematic function. I observe the same slowdown as in the example program: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx and with the following snippet:

 #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 to fix or trick this problem? I can create temporary files myself and avoid calling NetworkInterface.getNetworkInterfaces, but SecureRandom is used throughout the standard Java library. Is there a way to make SecureRandom not use GetIfTable?

Java version:

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

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

Problem 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) 
+44
java performance windows windows-7 networking
Aug 14 '16 at 13:04 on
source share
1 answer

The default implementation of SecureRandom scans network interfaces as an additional source of system entropy. To avoid this, you need to register a custom java.security.Provider that contains a different implementation of SecureRandomSpi .

Fortunately, the JDK for Windows already has a suitable implementation of SecureRandomSpi , which relies on the Microsoft Crypto API: sun.security.mscapi.PRNG . Although this is not a public API, the class exists in all versions of OpenJDK and Oracle JDK from 1.6 to 9, and backup access is available anyway.

There are two ways to register MS Crypto PRNG as the default SecureRandom algorithm.

1. Inside the application, calling WindowsSecureRandom.register() at the very beginning.

 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. Reordering the list of providers in the %JAVA_HOME%\jre\lib\security\java.security file.

 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 have verified that with any SeedGenerator and NetworkInterface classes no longer load.

+29
Aug 14 '16 at 16:18
source share



All Articles