插入USB热点后,简单的Java程序速度降低了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
奇怪的是,这里没有任何东西实际上通过networking传输 – 插入的networking适配器应该不重要。
我做了一个回溯,看起来大部分时间都花在了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
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
似乎是有问题的function。 我正在观察示例程序中的同样的放缓: 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; }
如何解决或解决此问题? 我可以自己创build临时文件,避免调用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
有问题的networking适配器:
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)
SecureRandom
默认实现将networking接口扫描为系统熵的附加源。 为了避免这种情况,你需要注册一个自定义的java.security.Provider
,它包含一个不同的SecureRandomSpi
实现。
幸运的是,JDK for Windows已经有一个合适的SecureRandomSpi
实现,它依赖于Microsoft Crypto API: sun.security.mscapi.PRNG
。 虽然这是非公开的API,但该类存在于OpenJDK和Oracle JDK的所有版本中,从1.6到9,并且可以使用后备。
有两种方法将MS Crypto PRNG注册为默认的SecureRandomalgorithm。
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
文件中重新sorting提供者列表。
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 ...
我已经validation,无论是解决schemeSeedGenerator
和NetworkInterface
类不再加载。