使用 VisualVM 进行性能分析及调优

2023-11-03

一、概述

开发大型 Java 应用程序的过程中难免遇到内存泄露、性能瓶颈等问题,比如文件、网络、数据库的连接未释放,未优化的算法等。随着应用程序的持续运行,可能会造成整个系统运行效率下降,严重的则会造成系统崩溃。为了找出程序中隐藏的这些问题,在项目开发后期往往会使用性能分析工具来对应用程序的性能进行分析和优化。

VisualVM 是一款免费的性能分析工具。它通过 jvmstat、JMX、SA(Serviceability Agent)以及 Attach API 等多种方式从程序运行时获得实时数据,从而进行动态的性能分析。同时,它能自动选择更快更轻量级的技术尽量减少性能分析对应用程序造成的影响,提高性能分析的精度。

本文将对 VisualVM 的主要功能逐一介绍并探讨如何利用获得的数据进行性能分析及调优。IBM开发文档

二、背景知识:性能分析的主要方式

1.监视:监视是一种用来查看应用程序运行时行为的一般方法。通常会有多个视图(View)分别实时地显示 CPU 使用情况、内存使用情况、线程状态以及其他一些有用的信息,以便用户能很快地发现问题的关键所在。

2.转储:性能分析工具从内存中获得当前状态数据并存储到文件用于静态的性能分析。Java 程序是通过在启动 Java 程序时添加适当的条件参数来触发转储操作的。它包括以下三种:

系统转储:JVM 生成的本地系统的转储,又称作核心转储。一般的,系统转储数据量大,需要平台相关的工具去分析,如 Windows 上的 windbg 和 Linux 上的 gdb.

Java 转储:JVM 内部生成的格式化后的数据,包括线程信息,类的加载信息以及堆的统计数据。通常也用于检测死锁。

堆转储:JVM 将所有对象的堆内容存储到文件。

3.快照:应用程序启动后,性能分析工具开始收集各种运行时数据,其中一些数据直接显示在监视视图中,而另外大部分数据被保存在内部,直到用户要求获取快照,基于这些保存的数据的统计信息才被显示出来。快照包含了应用程序在一段时间内的执行信息,通常有 CPU 快照和内存快照两种类型。

CPU 快照:主要包含了应用程序中函数的调用关系及运行时间,这些信息通常可以在 CPU 快照视图中进行查看。

内存快照:主要包含了内存的分配和使用情况、载入的所有类、存在的对象信息及对象间的引用关系等。这些信息通常可以在内存快照视图中进行查看。

4.性能分析:性能分析是通过收集程序运行时的执行数据来帮助开发人员定位程序需要被优化的部分,从而提高程序的运行速度或是内存使用效率,主要有以下三个方面:

CPU 性能分析:CPU 性能分析的主要目的是统计函数的调用情况及执行时间,或者更简单的情况就是统计应用程序的 CPU 使用情况。通常有 CPU 监视和 CPU 快照两种方式来显示 CPU 性能分析结果。

内存性能分析:内存性能分析的主要目的是通过统计内存使用情况检测可能存在的内存泄露问题及确定优化内存使用的方向。通常有内存监视和内存快照两种方式来显示内存性能分析结果。

线程性能分析:线程性能分析主要用于在多线程应用程序中确定内存的问题所在。一般包括线程的状态变化情况,死锁情况和某个线程在线程生命期内状态的分布情况等

三、VisualVM 安装

1、VisualVM 安装

VisualVM 是一个性能分析工具,自从 JDK 6 Update 7 以后已经作为 Oracle JDK 的一部分,位于 JDK 根目录的 bin 文件夹下。VisualVM 自身要在 JDK6 以上的版本上运行,但是它能够监控 JDK1.4 以上版本的应用程序。

VisualVM可以使用JDK自带的jvisualvm(bin目录下)也可以单独下载,经过实验,发现安装后的JDK中自带的jvisualvm包含的插件比较少大概有五六个左右,单独下载的插件包含的比较多大概有24个左右。它也可以监控1.6以前的JDK,但是对某些模块支持的并不是很好,无法显示。

2、安装 VisualVM 上的插件

VisualVM 插件中心提供很多插件以供安装向 VisualVM 添加功能。可以通过 VisualVM 应用程序安装,或者从 VisualVM 插件中心手动下载插件,然后离线安装。另外,用户还可以通过下载插件分发文件 (.nbm 文件 ) 安装第三方插件为 VisualVM 添加功能。

从 VisualVM 插件中心安装插件安装步骤 :

1、从主菜单中选择“工具”>“插件”。 
2、在“可用插件”标签中,选中该插件的“安装”复选框。单击“安装”。 
3、逐步完成插件安装程序

这里写图片描述

根据 .nbm 文件安装第三方插件安装步骤 :

1、从主菜单中选择“工具”>“插件”。 
2、在“已下载”标签中,点击”添加插件”按钮,选择已下载的插件分发文件 (.nbm) 并打开。 
3、选中打开的插件分发文件,并单击”安装”按钮,逐步完成插件安装程序

这里写图片描述

四、功能介绍

下面我们将介绍性能分析的几种常见方式以及如何使用 VisualVM 性能分析工具进行分析。

1、内存分析 
VisualVM 通过检测 JVM 中加载的类和对象信息等帮助我们分析内存使用情况,我们可以通过 VisualVM 的监视标签和 Profiler 标签对应用程序进行内存分析。 
在监视标签内,我们可以看到实时的应用程序内存堆以及永久保留区域的使用情况。 
内存堆使用情况 
这里写图片描述

永久保留区域使用情况 
这里写图片描述

此外,我们也可以通过 Applications 窗口右击应用程序节点来启用“在出现 OOME 时生成堆 Dump”功能,当应用程序出现 OutOfMemory 例外时,VisualVM 将自动生成一个堆转储。 
开启“在出现 OOME 时生成堆”功能 
这里写图片描述 
在 Profiler 标签,点击“内存”按钮将启动一个内存分析会话,等 VisualVM 收集和统计完相关性能数据信息,将会显示在性能分析结果。通过内存性能分析结果,我们可以查看哪些对象占用了较多的内存,存活的时间比较长等,以便做进一步的优化。 
此外,我们可以通过性能分析结果下方的类名过滤器对分析结果进行过滤。 
内存分析结果 
这里写图片描述

2、CPU 分析 
VisualVM 能够监控应用程序在一段时间的 CPU 的使用情况,显示 CPU 的使用率、方法的执行效率和频率等相关数据帮助我们发现应用程序的性能瓶颈。我们可以通过 VisualVM 的监视标签和 Profiler 标签对应用程序进行 CPU 性能分析。

在监视标签内,我们可以查看 CPU 的使用率以及垃圾回收活动对性能的影响。过高的 CPU 使用率可能是由于我们的项目中存在低效的代码,可以通过 Profiler 标签的 CPU 性能分析功能进行详细的分析。如果垃圾回收活动过于频繁,占用了较高的 CPU 资源,可能是由内存不足或者是新生代和旧生代分配不合理导致的等。 
CPU 使用情况 
这里写图片描述 
在 Profiler 标签,点击“CPU”按钮启动一个 CPU 性能分析会话 ,VisualVM 会检测应用程序所有的被调用的方法。当进入一个方法时,线程会发出一个“method entry”的事件,当退出方法时同样会发出一个“method exit”的事件,这些事件都包含了时间戳。然后 VisualVM 会把每个被调用方法的总的执行时间和调用的次数按照运行时长展示出来。

此外,我们也可以通过性能分析结果下方的方法名过滤器对分析结果进行过滤。 
CPU 性能分析结果 
这里写图片描述

3、线程分析 
Java 语言能够很好的实现多线程应用程序。当我们对一个多线程应用程序进行调试或者开发后期做性能调优的时候,往往需要了解当前程序中所有线程的运行状态,是否有死锁、热锁等情况的发生,从而分析系统可能存在的问题。

在 VisualVM 的监视标签内,我们可以查看当前应用程序中所有活动线程和守护线程的数量等实时信息。 
活跃线程情况 
这里写图片描述 
VisualVM 的线程标签提供了三种视图,默认会以时间线的方式展现。另外两种视图分别是表视图和详细信息视图。

时间线视图上方的工具栏提供了缩小,放大和自适应三个按钮,以及一个下拉框,我们可以选择将所有线程、活动线程或者完成的线程显示在视图中。 
线程时间线视图 
这里写图片描述

线程表视图 
这里写图片描述 
我们在详细信息视图中不但可以查看所有线程、活动线程和结束的线程的详细数据,而且也可以查看某个线程的详细情况。 
线程详细视图 
这里写图片描述

五、快照功能

我们可以使用 VisualVM 的快照功能生成任意个性能分析快照并保存到本地来辅助我们进行性能分析。快照为捕获应用程序性能分析数据提供了一个很便捷的方式因为快照一旦生成可以在任何时候离线打开和查看,也可以相互传阅。

VisualVM 提供了两种类型的快照: 
1、Profiler 快照:当有一个性能分析会话(内存或者 CPU)正在进行时,我们可以通过性能分析结果工具栏的“快照”按钮生成 Profiler 快照捕获当时的性能分析数据。 
Profiler 快照 
这里写图片描述

2、应用程序快照:我们可以右键点击左侧 Applications 窗口中应用程序节点,选择“应用程序快照”为生成一个应用程序快照。应用程序快照会收集某一时刻的堆转储,线程转储和 Profiler 快照,同时也会捕获 JVM 的一些基本信息。 
应用程序快照 
这里写图片描述

六、转储功能

1、线程转储的生成与分析

VisualVM 能够对正在运行的本地应用程序生成线程转储,把活动线程的堆栈踪迹打印出来,帮助我们有效了解线程运行的情况,诊断死锁、应用程序瘫痪等问题。 
线程标签及线程转储功能 
这里写图片描述

当 VisualVM 统计完应用程序内线程的相关数据,会把这些信息显示新的线程转储标签。 
线程转储结果 
这里写图片描述

2、堆转储的生成与分析

VisualVM 能够生成堆转储,统计某一特定时刻 JVM 中的对象信息,帮助我们分析对象的引用关系、是否有内存泄漏情况的发生等。 
监视标签及堆转储功能 
这里写图片描述

当 VisualVM 统计完堆内对象数据后,会把堆转储信息显示在新的堆转储标签内,我们可以看到摘要、类、实例数等信息以及通过 OQL 控制台执行查询语句功能。 
堆转储的摘要包括转储的文件大小、路径等基本信息,运行的系统环境信息,也可以显示所有的线程信息。 
堆转储的摘要视图 
这里写图片描述

从类视图可以获得各个类的实例数和占用堆大小数,分析出内存空间的使用情况,找出内存的瓶颈,避免内存的过度使用。 
堆转储的类视图 
这里写图片描述

通过实例数视图可以获得每个实例内部各成员变量的值以及该实例被引用的位置。首先需要在类视图选择需要查看实例的类。 
选择查询实例数的类 
这里写图片描述 
实例数视图 
这里写图片描述

此外,还能对两个堆转储文件进行比较。通过比较我们能够分析出两个时间点哪些对象被大量创建或销毁。 
堆转储的比较 
这里写图片描述 
堆转储的比较结果 
这里写图片描述 
线程转储和堆转储均可以另存成文件,以便进行离线分析。 
转储文件的导出 
这里写图片描述

七、实战分析

1、简要说明

打开jdk自带的jvisualvm(bin目录下),程序运行后会自动监控本机运行的java程序(Local标签下,远程服务器上的java程序需要另行配置),Local标签下的第一个VisualVM为jvisualvm对自身的监控,可以看到消耗的资源还是很少的,第二个为本机的eclipse。 
这里写图片描述

监控项总共分为Overview,Monitor,Threads和一个Sampler。 
(1)Overview(jvm启动参数,系统参数) 
这里写图片描述 
可以看到eclipse的启动参数 
这里写图片描述 
(通过这些启动参数,可以判断程序是否有内存溢出)

(2)Monitor 
这里写图片描述
左上:cpu利用率,gc状态的监控 
右上:堆利用率,永久内存区的利用率 
左下:类的监控 
右下:线程的监控 
performGC:gc的详细运行状态 
HeapDump:堆的详细状态(可以看到堆的概况,里面所有的类,还能点进具体的一个类查看这个类的状态)

(3)Threads 
这里写图片描述
能够显示线程的名称和运行的状态,在调试多线程时必不可少,而且可以点进一个线程查看这个线程的详细运行情况

2、监控服务器上的tomcat

tomcat的配置文件catalina.sh中增加:

JAVA_OPTS="-Dcom.sun.management.jmxremote.port=9998   
    -Dcom.sun.management.jmxremote.ssl=false   
    -Dcom.sun.management.jmxremote.authenticate=false   
    -Djava.rmi.server.hostname=192.168.58.164" 

参数说明:
指定了JMX启动的代理端口,这个端口就是visualvm要连接的端口(9998端口不能被别的程序使用netstat -an|gerp 9998)  
Dcom.sun.management.jmxremote.port=9998 

指定了JMX是否启用ssl  
Dcom.sun.management.jmxremote.authenticate=false  

指定了JMX是否启用鉴权(需要用户名,密码鉴权)  
Dcom.sun.management.jmxremote.authenticate=false  

指定了服务器主机名  
Djava.rmi.server.hostname=192.168.58.164  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这里写图片描述 
填写主机名: 
这里写图片描述 
右键创建一个jmx连接,填写上ip:port即可: 
这里写图片描述

3、监控服务器上的java程序

相较于监控tomcat要麻烦很多,要预先启动jstatd服务(${java_home}/bin目录下) 
jstatd是一个监控JVM从创建到销毁过程中资源占用情况并提供远程监控接口的RMI(Remote Method Invocation,远程方法调用)服务器程序,它是一个Daemon程序(后台进程),要保证远程监控软件连接到本地的话需要jstatd始终保持运行。

jstatd运行需要通过-J-Djava.security.policy=*指定安全策略,因此我们需要在服务器上建立一个指定安全策略的文件jstatd.all.policy(我放在了${java_home}/bin目录下),文件内容如下:

grant codebase "file:/home/123/123/jdk1.5.0_15/lib/tools.jar" {   
    permission java.security.AllPermission;   
};   
  • 1
  • 2
  • 3

然后使用这个策略文件启动jstatd服务

[sys@sys bin]$ pwd  
/home/sys/jdk1.5.0_15/bin  
[sys@123 sys]$ ./jstatd -J-Djava.security.policy=./jstatd.all.policy & 
  • 1
  • 2
  • 3

因为监控的过程中需要jstatd服务一直运行,所以加上了&,如果需要日志也可使用:

./jstatd -J-Djava.security.policy=./jstatd.all.policy -J-Djava.rmi.server.logCalls=true  
  • 1

接下来就可以在jvisualvm中配置监控该服务器上运行的java程序了,和在jvisualvm中配置监控tomcat服务器的操作过程是一样的。需要特别注意的是,有时在配置远程监控java程序的时候jvisualvm会报一个错误 
点击查看错误详情: 
这里写图片描述 
connection refused to host:127.0.0.1初步判断和主机名有关系。

[sys@sys bin]# hostname -i  
127.0.0.1  

[sys@sys bin]# hostname 192.168.58.168 
  • 1
  • 2
  • 3
  • 4

修改完重启jstatd服务(网上很多人说要修改主机的/etc/hosts文件,但是我自己测试修改/etc/hosts文件是没有效果的,必须要修改主机名),Add Rempte Host,填写主机名,之后这里要选择添加一个jstatd连接: 
这里写图片描述 
直接选择默认配置即可(默认使用1099端口): 
这里写图片描述 
点击ok后,168上的所有java程序就会自动列出: 
这里写图片描述

注意:推荐一个非常好用的插件VisualGC,tool -> plugin ->aviable plugin: 
这里写图片描述
安装完这个插件后,将会增加新的监控条目Visual GC,可以看到虚拟机内存各个区的使用情况: 
这里写图片描述

4、模拟内存泄漏

import java.util.HashMap;  
import java.util.Map;  
public class MemoryLeckTest {  
    //声明缓存对象  
    private static final Map map = new HashMap();  
    public static void main(String args[]){  
        try {  
            Thread.sleep(10000);//给打开visualvm时间  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        //循环添加对象到缓存  
        for(int i=0; i<1000000;i++){  
            TestMemory t = new TestMemory();  
            map.put("key"+i,t);  
        }  
        System.out.println("first");  
        //为dump出堆提供时间  
        try {  
            Thread.sleep(10000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        for(int i=0; i<1000000;i++){  
            TestMemory t = new TestMemory();  
            map.put("key"+i,t);  
        }  
        System.out.println("second");  
        try {  
            Thread.sleep(10000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        for(int i=0; i<3000000;i++){  
            TestMemory t = new TestMemory();  
            map.put("key"+i,t);  
        }  
        System.out.println("third");  
        try {  
            Thread.sleep(10000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        for(int i=0; i<4000000;i++){  
            TestMemory t = new TestMemory();  
            map.put("key"+i,t);  
        }  
        System.out.println("forth");  
        try {  
            Thread.sleep(Integer.MAX_VALUE);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("qqqq");  
    }  
}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

配置的JVM参数如下:

-Xms512m  
-Xmx512m  
 -XX:-UseGCOverheadLimit  
 -XX:MaxPermSize=50m  
  • 1
  • 2
  • 3
  • 4

使用jVisualvm分析内存泄漏:

查看Visual GC标签,内容如下,这是输出first的截图 
这里写图片描述
这是输出forth的截图: 
这里写图片描述
通过2张图对比发现: 
这里写图片描述 
老生代一直在gc,当程序继续运行可以发现老生代gc还在继续: 
这里写图片描述 
增加到了7次,但是老生代的内存并没有减少。说明存在无法被回收的对象,可能是内存泄漏了。 
如何分析是那个对象泄漏了呢?打开抽样器标签:点击后如下图: 
这里写图片描述
按照程序输出进行堆dump,当输出second时,dump一次,当输出forth时dump一次。 
进入最后dump出来的堆标签,点击类: 
这里写图片描述 
点击右上角:“与另一个堆存储对比”。如图选择第一次导出的dump内容比较: 
这里写图片描述 
比较结果如下: 
这里写图片描述 
可以看出在两次间隔时间内TestMemory对象实例一直在增加并且多了,说明该对象引用的方法可能存在内存泄漏。 
如何查看对象引用关系呢? 
右键选择类TestMemory,选择“在实例视图中显示”,如下所示: 
这里写图片描述
左侧是创建的实例总数,右侧上部为该实例的结构,下面为引用说明,从图中可以看出在类CyclicDependencies里面被引用了,并且被HashMap引用。如此可以确定泄漏的位置,进而根据实际情况进行分析解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 VisualVM 进行性能分析及调优 的相关文章

  • Google 地图查询返回的 JSON 包含像 \x26 这样的编码字符(如何解码?)

    在 Java 应用程序中 我获取 JSON 来自 Google 地图 其中包含以下字符 x26我想将其转换为其原始字符 据我所知 这是一个 UTF 8 表示法 但我不完全确定 在源 JSON 中 可能会出现各种编码字符 例如 x3c div
  • 用 @DataJpaTest 注释的测试不是用 @Autowired 注释的自动装配字段

    我有一个 Spring Boot 应用程序 其中包含 Spring Data Jpa 存储库 我需要围绕这个存储库运行单元 或组件 测试 我对 Spring Data Jpa 没有太多经验 这是我的测试 这很简单 我无法让它通过 impor
  • 如何打印整个字符串池?

    我想打印包含文字的整个字符串池String使用添加的对象intern 就在垃圾收集之前 JDK有没有隐式的方法来进行这样的操作 我们如何检查字符串池 EDIT The comment suggests that there may be a
  • 将链接对象转换为流或集合

    我想迭代堆栈跟踪 堆栈跟踪由可抛出对象组成 其 getCause 返回下一个可抛出对象 最后一次调用 getCause 返回 null 示例 a gt b gt null 我尝试使用 Stream iterable 这会导致 NullPoi
  • 如何对 IntStream 进行逆序排序

    我正在使用 txt 文件读取数字BufferedReader 我想颠倒该流中元素的顺序 以便在收集它们时 它们将从最高到最低排列 我不想在构建数组后进行排序 因为我不知道其中可能有多少元素 我只需要最高的 N 个元素 in new Buff
  • Google Inbox 类似 RecyclerView 项目打开动画

    目前 我正在尝试实现 Google Inbox 例如RecyclerView行为 我对电子邮件打开动画很好奇 我的问题是 该怎么做 我的意思是 他们使用了哪种方法 他们用过吗ItemAnimator dispatchChangeStarti
  • 服务器到 Firebase HTTP POST 结果为响应消息 200

    使用 Java 代码 向下滚动查看 我使用 FCM 向我的 Android 发送通知消息 当提供正确的服务器密钥令牌时 我收到如下所示的响应消息 之后从 FCM 收到以下响应消息 Response 200 Success Message m
  • 场景生成器删除 fxml 文件中的导入

    我使用场景构建器 Gluon Scene Builder JavaFX Scene Builder 8 1 1 来创建应用程序的 UI 并使用 Eclipse 开发 JavaFX 现在 每次我在场景生成器中保存某些内容时 它都会从 fxml
  • Java替换特定字符

    这是我在这个网站上的第一个问题 所以我会尽量不要成为一个十足的菜鸟 我目前正在用java 创建刽子手游戏 所以我问你的问题是我们是否被赋予了 幽灵 这个词 并将 Ghost 替换为 hiddenWord ghost length for i
  • 具有多种值类型的 Java 枚举

    基本上我所做的是为国家编写一个枚举 我希望不仅能够像国家一样访问它们 而且还能够访问它们的缩写以及它们是否是原始殖民地 public enum States MASSACHUSETTS Massachusetts MA true MICHI
  • 从 html 页面和 javascript 调用 java webservice

    我正在尝试从 javascript 调用 java 实现的 Web 服务 使用 NetBeans IDE 我读过很多关于 jQuery 和 AJAX 的内容 但我似乎无法掌握它 假设我的 Web 服务 WSDL 位于 http localh
  • Apache Commons CLI:替代已弃用的 OptionBuilder?

    IntelliJ 显示此示例代码中不推荐使用 OptionBuilderhttp commons apache org proper commons cli usage html http commons apache org proper
  • 不兼容的类型:在 java netbeans 中对象无法转换为 String

    我试图在我的项目中使用对象数组 但出现错误 incompatible types Object cannot be converted to String 在这一行 ST1 new String emt1 emt2 emt3 emt4 现在
  • 从 Stax XMLStreamReader 读取以解组部分

    我正在使用 Stax 游标 API 从大型 xml 文件中提取数据 当前 我转到特殊标签的开头并使用 JAXB 解组该标签 这对于格式良好的 xml 文件效果很好 但不久前我有一个文档 其中数十万个标签中有一个未关闭 JAXB 使用 XML
  • 如何在keycloak中动态编辑standalone.xml文件

    我正在尝试通过 docker 编辑standalone xml 并尝试添加 但 keycloak 正在使用它standalone xml 但我可以看到standalone xml 文件中的更改 我需要在standalone xml 文件中添
  • 使用 Java 从 S3 上的文件在 S3 上创建 zip 文件

    我在 S3 上有很多文件 需要对其进行压缩 然后通过 S3 提供压缩文件 目前 我将它们从流压缩到本地文件 然后再次上传该文件 这会占用大量磁盘空间 因为每个文件大约有 3 10MB 而且我必须压缩多达 100 000 个文件 所以一个 z
  • 我想要一个 Java 阿拉伯语词干分析器

    我正在寻找阿拉伯语的 Java 词干分析器 我找到了一个名为 AraMorph 的库 但它的输出是无法控制的 并且它会形成不需要的单词 还有其他阿拉伯语词干分析器吗 这是新的阿拉伯语词干分析器 Assem 的阿拉伯语轻词干分析器 http
  • 如何移动图像(动画)?

    我正在尝试在 x 轴上移动船 还没有键盘 我如何将运动 动画与boat png而不是任何其他图像 public class Mama extends Applet implements Runnable int width height i
  • Path2D 上的鼠标指针检测

    我构建了一个Path2D http docs oracle com javase 7 docs api java awt geom Path2D html表示由直线组成的未闭合形状 我希望能够检测何时单击鼠标并且鼠标指针靠近路径 在几个像素
  • 从一个文本文件中获取数据并将其移动到新的文本文件

    我有一个文件 里面有数据 在我的主要方法中 我读入文件并关闭文件 我调用另一种方法 在原始文件的同一文件夹内创建一个新文件 所以现在我有两个文件 原始文件和通过我调用的方法生成的文件 我需要另一种方法 从原始文件中获取数据并将其写入创建的新

随机推荐

  • Ubuntu下安装goLand

    Ubuntu下安装GoLand 官网下载golang包 Other Versions GoLand 下载的是goland 2018 1 6 tar版本 更高的版本不容易激活 将程序解压至 usr local tar zxvf goland
  • 知识体系之APUE/内核编程

    目录 一 APUE 内核编程 1 基本概念与实现 1 1 进程3态 1 1 1 进程调度的方式 1 1 2 调度原则 1 1 3 调度算法 1 2 僵尸进程 孤儿进程 1 2 1 僵尸进程 1 2 2 孤儿进程 1 3 pread pwri
  • 前端-html-01

    1 前端开发 自学html css学习笔记 1 1 绝对路径 链接一张图的图片 img src 网页链接 本地连接 1 2 文本格式化 字体被 strong 加粗 strong 了 br 字体 em 倾斜 em br 我是
  • AI教程 如何在 Illustrator 中转换图稿?

    欢迎观看Illustrator教程 小编带大家学习 Illustrator 2022的基本工具和使用技巧 了解如何在 Illustrator 中应用旋转 反射和剪切转换图稿 在本文中我们将使用左侧的部件组装这枚火箭 并探索反射 剪切 旋转和
  • 使用python爬取豆瓣

    https www runoob com python python json html 我的理解就是告诉网站那边的人我是通过浏览器访问的 防止它分辨出我不是正常用户访问网站 这里要注意爬数据和调接口不是一回事 调接口我们是直接请求后端的数
  • [管理与领导-78]:IT基层管理者 - 核心技能 - 高效执行力 - 3 - 执行力的核心是拿到结果(ougput),而不是任务(input),也不是执行(过程、加工)

    前言 执行力的核心是结果 但并非所有人都理解 结果 对执行力的意义和作用 本文就是探讨对 结果 的理解 一 执行中常见的困惑 1 1 员工的困惑 接收任务 员工在执行工作过程中可能会遇到各种困惑 以下是一些可能的困惑情况 任务不清晰 员工可
  • 当 App 有了系统权限,真的可以为所欲为?

    看到群里发了两篇文章 出于好奇 想看看这些个 App 在利用系统漏洞获取系统权限之后 都干了什么事 于是就有了这篇文章 由于准备仓促 有些 Code 没有仔细看 感兴趣的同学可以自己去研究研究 多多讨论 深蓝洞察 2022 年度最 不可赦
  • GC 日志

    VM 参数 XX PrintGCDetails Xms30M Xmx30M Xmn10M 代码 import java lang management ManagementFactory import java lang managemen
  • log4j同步机制导致的cpu飙升排查与解决

    问题 组内某业务的几个相关接口均超时 上阿里云查日志一看是Dubbo调用超时 查看网络情况未发现异常 直接上Provider的机器查看占用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 to
  • 两段锁(2PL)理解

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 两段锁即两阶段锁 Two phase locking 2PL 首先 两阶段锁强调的是 加锁 增长阶段 growing phase 和解锁 缩减阶段 shrinking ph
  • 正割、余割、正弦、余弦、正切、余切之间的关系的公式 sec、csc与sin、cos、tan、cot之间的各种公式...

    1 倒数关系 tan cot 1 sin csc 1 cos sec 1 2 商数关系 tan sin cos cot cos sin 3 平方关系 sin cos 1 1 tan sec 1 cot csc 4 求导关系 sec sect
  • golang os/exec 执行终端命令

    1 只执行命令 不获取结果 直接调用 Cmd 对象的 Run 函数 返回的只有成功和失败 获取不到任何输出的结果 package main import log os exec func main cmd exec Command ls l
  • Kali Linux安装pip2

    问题说明 随着pytho3的强袭崛起 Kali 2020的版本去除了pip2 由于很多之前的黑客工具都是由python2写的 需要通过pip2来安装相应的模块 解决方法 Step 1 下载get pip py wget https boot
  • VSCODE中开发AE脚本环境搭建流程(Visual Studio Code for Adobe ExtendScript)

    VSCODE中开发AE脚本环境搭建流程 Visual Studio Code for Adobe ExtendScript 一 下载VSCODE 下载地址 https code visualstudio com 二 插件下载和配置 Adob
  • Qt中的布局浅析与弹簧的使用,以及Qt居中的两种方法

    1 布局 为什么要布局 布局之后窗口的排列是有序的 布局之后窗口的大小发生变化 控件的大小也会对应变化 如果不对控件布局 窗口显示出来之后有些控件的看不到的 布局是可以嵌套使用 常用的布局方式 水平布局 gt 所有的控件水平排列 gt 一行
  • 电子工程师必知必会——矢网史密斯Smith Chart圆图测试阻抗

    史密斯圆图是由很多圆周交织在一起的一个图 正确的使用它 可以在不作任何计算的前提下得到一个表面上看非常复杂的系统的匹配阻抗 唯一需要作的就是沿着圆周线读取并跟踪数据 本期视频贝贝就带大家学习矢网的史密斯圆图如何测试负载的阻抗 一起来学习吧
  • clickhouse代理chproxy安装部署实战最详细全网独一份

    安装chproxy 操作系统 centos7 X64 chproxy 是clickhouse官方列出的开源代理服务 go语言开发 https github com ContentSquare chproxy github下载地址 第1步下载
  • Springboot 多线程实现事务控制

    业务背景 工作中有很多 在一个service实现层 有可能调用其他的service 或者说是使用异步线程 这样就不容易控制当前操作成功和失败 不多说 上代码 获取数据库事务控制器 Component public class Transac
  • 流利说 Level 4 全文

    Level 4 Unit 1 1 4 Listening Lesson 1 Visiting a Friend 1 2 Lesson2 Vocabulary Lesson 3 Pains and Sickness Lesson 4 Land
  • 使用 VisualVM 进行性能分析及调优

    一 概述 开发大型 Java 应用程序的过程中难免遇到内存泄露 性能瓶颈等问题 比如文件 网络 数据库的连接未释放 未优化的算法等 随着应用程序的持续运行 可能会造成整个系统运行效率下降 严重的则会造成系统崩溃 为了找出程序中隐藏的这些问题