草庐IT

Java VisualVM 为 CPU 分析提供了奇怪的结果 - 还有其他人遇到过这个吗?

coder 2023-05-18 原文

我编写了这个小(而且效率极低)的类,并希望使用 Java VisualVM 对其进行分析。

public class Test {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        br.readLine();
        int n = Integer.parseInt(args[0]);
        int fib = fib(n);
        System.out.println(fib);
    }

    private static int fib(int n) {
        if (n < 2) {
            return n;
        }
        return fib(n-1)+fib(n-2);
    }
}

结果很奇怪。结果完全由对 ConnectionHandler.run() 的调用支配。

(98.2%) sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run()
(1.7%) java.lang.Thread.join(long)
(0%) java.lang.String.equals(Object)
等等……

大概有大约一百种方法被分析,其中没有一个是 fib(int)!

令人难以置信的是,我的程序实际上将所有时间都花在了这些方法上。他们似乎是连接到我的 jvm 并做它的事情的分析器。

我做错了什么?

为清楚起见进行了编辑:如果您为 n 传递 45,则此应用程序将运行 20 秒。我最初分析的程序(不是斐波那契计算器)将我的 cpu 上的所有四个内核都固定在 100% 上,而我的分析运行持续时间长达 5 分钟。这些具有相同的结果,并且我的应用程序中的方法没有出现在热点方法列表中。

它因运行而异,但 ConnectionHandler.run() 始终位于顶部,通常占分析时间的约 99%。

第二次编辑:我尝试使用采样器,现在得到的结果与 JProfiler 产生的结果一致。这样做的缺点是我没有得到分析附带的堆栈跟踪信息。但对于我的迫切需要,这非常好。

我在玩游戏时发现的一点是,VisualVM 在分析方法调用时会计算挂钟时间。

在我的具体情况下,我的应用程序有一个主线程,它启动工作线程并立即阻塞等待队列中的消息。

这意味着阻塞方法似乎会占用分析器上的几乎所有时间,尽管事实上并不是这种方法占用了我的 CPU。

我希望 sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run() 方法也是如此,它可以很好地完成工作 - 但是当它终止时,它会成为我的应用程序中运行时间最长的方法之一- 反复

最佳答案

我不认为这是不可思议的。您有一个应用程序,其中“有效负载”非常小(尽管这当然取决于 n 的值),并且您必须接受所需的额外工作(连接分析器并将所有信息转移到它) 将淹没该有效载荷。

这不是我首先要分析的那种应用程序,因为很明显大量时间将花费在 fib 上。无论如何(对于 n 的重要值),将其标记为明显的优化目标。

我更倾向于将分析器用于更重要的应用程序,其中:

  • 优化工作应该去哪里并不明显;和
  • payload 中有大量工作要做。

如果你真的想测试那个代码,你可能需要通过(例如)替换来提高它的效果:

int fib = fib(n);

与:

for (int i = 0; i < 100000; i++) {
    int fib = fib(n);
)

我会告诉你一件需要注意的事情。我不知道任何特定 JVM 的内部结构,但是使用递归方法来减少参数的速度很慢通常是一个坏主意,这会导致堆栈空间很快耗尽。

我的意思是,二分搜索是一个很好的候选,因为它在每个递归级别中删除了一半的剩余搜索空间(因此十亿个项目的搜索空间只有 30 个级别)。

另一方面,对数字 1,000,000,000 的斐波那契数列使用递归将需要大约 10 亿个级别,而大多数堆栈都很难包含这些。

尾端递归优化可能会避免该问题,但您需要小心以防优化未完成。

关于Java VisualVM 为 CPU 分析提供了奇怪的结果 - 还有其他人遇到过这个吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5385991/

有关Java VisualVM 为 CPU 分析提供了奇怪的结果 - 还有其他人遇到过这个吗?的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  4. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  5. 报告回顾丨模型进化狂飙,DetectGPT能否识别最新模型生成结果? - 2

    导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri

  6. ruby-on-rails - 浮点乘法的 Ruby 奇怪问题 - 2

    有没有人用ruby​​解决这个问题:假设我们有:a=8.1999999我们想将它四舍五入为2位小数,即8.20,然后乘以1,000,000得到8,200,000我们是这样做的;(a.round(2)*1000000).to_i但是我们得到的是8199999,为什么?奇怪的是,如果我们乘以1000、100000或10000000而不是1000000,我们会得到正确的结果。有人知道为什么吗?我们正在使用ruby​​1.9.2并尝试使用1.9.3。谢谢! 最佳答案 每当你在计算中得到时髦的数字时使用bigdecimalrequire'bi

  7. ruby-on-rails - 不兼容的库版本 : nokogiri. bundle 需要 8.0.0 或更高版本,但 libiconv.2.dylib 提供 7.0.0 版本 - 2

    为了在我的mac上为一个rails项目安装mysql,我遵循了安装Homebrew软件和删除mac端口的在线建议。这是问题开始的地方。rails项目不会构建,我得到这个:[rake--prereqs]rakeaborted!dlopen(/Users/Parker/.rvm/gems/ruby-1.9.3-p448/gems/nokogiri-1.6.0/lib/nokogiri/nokogiri.bundle,9):Librarynotloaded:/opt/local/lib/libiconv.2.dylibReferencedfrom:/Users/Parker/.rvm/gem

  8. ruby-on-rails - Rails 两条腿的 OAuth 提供商? - 2

    我有一个Rails2.3.5应用程序,其中包含我希望保护的API。没有用户-它是一个应用到应用风格的网络服务(更像是亚马逊服务而不是facebook),所以我想使用两条腿的OAuth方法来实现它。我一直在尝试使用oauth-plugin服务器实现作为开始:http://github.com/pelle/oauth-plugin...但它的构建需要三足(网络重定向流)oauth。在我深入研究对其进行更改以支持两条腿之前,我想看看是否有更简单的方法,或者是否有人有更好的方法让Rails应用程序实现成为两条腿的OAuth提供程序。 最佳答案

  9. ruby - 奇怪的 ruby​​ for 循环行为(为什么这样做有效) - 2

    defreverse(ary)result=[]forresult[0,0]inaryendresultendassert_equal["baz","bar","foo"],reverse(["foo","bar","baz"])这行得通,我想了解原因。有什么解释吗? 最佳答案 如果我使用each而不是for/in重写它,它看起来像这样:defreverse(ary)result=[]#forresult[0,0]inaryary.eachdo|item|result[0,0]=itemendresultendforainb基本上就

  10. ruby-on-rails - ruby数组奇怪的东西(无限数组) - 2

    当我写下面的代码时:x=[1,2,3]x我得到这个输出:[1,2,3,[...]][1,2,3,[...]][1,2,3,[...]]我不应该只得到[1,2,3,[1,2,3]]吗?解释是什么? 最佳答案 这没什么奇怪的。数组的第四个元素就是数组本身,所以当你求第四个元素时,你得到的是数组,当你求第四个元素的第四个元素时,你得到的是数组,当你求第四个元素时,你得到的是数组。第四个元素的第四个元素的第四个元素的元素......你得到了数组。就这么简单。唯一有点不寻常的是Array#to_s检测到这样的递归,而不是进入无限循环,而是返回

随机推荐