当前位置: 首页 > 面试题库 >

插入USB热点后,简单Java程序的速度降低了100倍

申炳
2023-03-14
问题内容

我有以下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)

反过来,这似乎花费了大部分时间在GetIfTableWindows 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似乎是有问题的功能。我在以下示例程序中都观察到相同的速度下降:https://msdn.microsoft.com/zh-
cn/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)

问题答案:

SecureRandom
扫描网络接口的默认实现是系统熵的附加来源。为了避免这种情况,您需要注册一个java.security.Provider包含的不同实现的自定义SecureRandomSpi

幸运的是,用于Windows的JDK已经具有SecureRandomSpi依赖于Microsoft Crypto API
的合适的实现:sun.security.mscapi.PRNG。尽管这是非公开的API,但是从1.6到9的所有版本的OpenJDK和Oracle
JDK中都存在该类,并且仍然可以使用后备。

有两种方法可以将MS Crypto PRNG注册为默认的SecureRandom算法。

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

我已经验证,解决方案SeedGeneratorNetworkInterface类都不会再加载。



 类似资料:
  • 帮助我减少这个程序的时间复杂性 输出:为每个测试用例输出这样的对的数量。 约束条件:T≤10;N≤100000;A[i]≤1000000 示例输入(明文链接)

  • 问题内容: 这是一个非常简单的查询: 之前花了15分钟,但是那是在Mysql安装中,缓冲池大小太小,15分钟就可以了,因为这是每月的工作。我升级到Mysql 5.7(从5.1或5.2之类的版本),因为最初的安装是32位的,所以我无法将innodb缓冲池的大小提高到该数据库所需的最小10gb(我在具有以下功能的计算机上将其设置为16GB): 32GB RAM。一个月后,我现在去运行此查询,但它在6个

  • 问题内容: 我之所以这样问是因为我使用Python,但是它也可以应用于其他解释语言(Ruby,PHP,JavaScript)。 每当我在代码中留下评论时,我是否会放慢解释器的速度?根据我对解释器的有限了解,它以字符串形式读取程序表达式,然后将这些字符串转换为代码。似乎每次解析评论时都是浪费时间。 是这样吗 是否有一些解释性语言的注释约定,或者其影响可以忽略不计? 问题答案: 对于Python而言,

  • 我正在处理一个聊天应用程序,我有一些问题显示聊天消息。对于存储,我使用了一个Room数据库,为了显示消息,我使用了一个RecyclerView。问题是,activity变得非常慢,在滚动信息时没有那么好的响应。 下面是我的代码: ChatActivity.java AppDatabase.java MessageDao.java ChatAdapter.java ChatitemViewWhold

  • 我正在编写一个加密照片的应用程序,尽管它需要在类似画廊的活动中解密和显示缩略图。当然,您可以在不同的活动中单击并查看全尺寸图像。我正在使用AES/CBC/PKCS7Padding密码和256位密钥。我使用PBEWithSHA256and256biates CBC BC导出密码密钥,并将其存储到内存中。然后,所有需要进行加密/解密的线程都在使用内存中的密钥初始化密码对象。 所以这是我的问题。当我同时