加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡水站长网 (https://www.0318zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 动态 > 正文

确认了!不办5G套餐,照样可以上5G网络?

发布时间:2021-01-29 13:57:05 所属栏目:动态 来源:互联网
导读:最上层是应用程序,应用程序一般只和标准库打交道(当然,我们也可以绕过标准库),标准库通过系统调用和操作系统交互,操作系统管理底层硬件。这就是为什么在C语言下同样的open函数既能在Linux下打开文件也能在Windows下打开文件的原因。说了这么多,这和mall

最上层是应用程序,应用程序一般只和标准库打交道(当然,我们也可以绕过标准库),标准库通过系统调用和操作系统交互,操作系统管理底层硬件。这就是为什么在C语言下同样的open函数既能在Linux下打开文件也能在Windows下打开文件的原因。说了这么多,这和malloc又有什么关系呢?

主角登场

原来,我们分配内存时使用的malloc函数其实不是实现在操作系统里的,而是在标准库中实现的。
 

你可能有些疑惑,什么,还有系统调用这种东西,为什么我没调用过也可以打开文件、进行网络通信?

标准库

虽然我们可以通过系统让操作系统替我们完成一些特定任务,但这些系统调用都是和操作系统强相关的,Linux和Windows的系统调用就完全不同。如果你直接使用系统调用的话,那么Linux版本的程序就没有办法在Windows上运行,因此我们需要某种标准,该标准对程序员屏蔽底层差异,这样程序员写的程序就无需修改的在不同操作系统上运行了。在C语言中,这就是所谓的标准库。注意,标准库代码也是运行在用户态的,并不是神仙(操作系统),一般来说,我们调用标准库去打开文件、网络通信等等,标准库再根据操作系统选择对应的系统调用。从分层的角度看,我们的程序一般都是这样的汉堡包类型:
 

而JVM 将热方法编译生成的机器码,由于是针对当前平台,当前硬件生成的,对应用具体执行情况分析之后进行编译而成,所以就像老手一样,能更了解情况,效率当然更高。

默默在背后做编译工作的人就是 JIT (Just-In-Time) 编译器,一般也叫即时编译器。

今天我们一起来看看,这越跑越快的背后,JIT 具体是怎样工作的。

我们都知道,Java 原生就是解释型语言,也是解释执行的,怎么又有了编译执行了?

执行 java -version 的时候,我们一般能看到当前 Java 版本号之后,会有一个 mixed mode,说明当前JVM 运行在混合模式之下,即同时包含解释执行和编译执行。我们也可以通过参数强制执行只按一种模式执行。各种环境根据自己的需要选择执行的方式。

相比编译执行,解释执行要慢很多,但仍然广泛在被运用在各种虚拟机中,比如它内存占用少,应用启动时间更短。更关键的优势在于它简单。一种新语言或者一个语言的新特性出现时,在解释器中能比编译器实现要快很多。另外,开发者会考虑到性价比,一些语言特性很难,同时也不值得在实现在编译器就只使用解释器。

开发实现语言时,使用解释器只有两个要求:

  1. 熟悉VM实现语言
  2. 理解新语言特性、语法和语义

而像在JIT编译器实现新语言特性,对开发者有更多的要求:

  • 熟悉目标机器的应用程序二进制接口规范
  • 把新语言特性映射到这个目标机器的接口运行时
  • 掌握开发编译器生成目标机器码的能力

而为了应用程序的执行效率、运行速度, Java 又特别需要JIT,在运行的适当时候,可以把一些高频率代码编译,换取更好的效率。

JIT就是通过将热方法、代码段编译生成机器码的形式,在下次调用到该方法时,会直接通过vtable中链接的机器码直接执行,所以效率是杠杠的。

那么问题来了,什么样的方法才算热方法,怎样来判断热方法?

对于热方法的计算,一般虚拟机内有以下几种实现方式:

  • 基于方法的JIT,JVM内常用
  • 基于踪迹的JIT, Dalvik和 TraceMonkey在使用
  • 基于区域的JIT,HHVM 使用这种形式

基于方法的JIT中,一般探测热点方法有基于采样的热点探测,即周期性的去检查线程的调用栈顶,如果方法经常出现在栈顶,那它就是热点方法。另一种是基于计数器的热点探测,这种会给每个方法建立计数器,用来统计方法的执行次数。超过阈值的就认为是热点方法。

当然需要注意的是,这里统计的次数,不是绝对的次数,和我们进行限流和降级时说的类似,都是一个时间周期内的相对频率,如果在此期间没有超过,就不算,原来的次数会减少。

JIT 编译的代码,存储在 Code Cache 的内存区间。空间是有限的在JVM 启动的时候,设置了一个固定的最大值,实现形式也是个堆,在分配满时会停止编译,类卸载、替换成新版本等也会从 Code Cache中删除。

另外,在JVM JIT编译器中包含C1、C2 两种编译器,在具体的编译过程中,一般是采用分层编译,再具体使用不同的编译器,相比C1,C2编译需要更多的时间,做更多的优化等等,像内联、循环展开、逃逸分析、锁消除与合并、栈上替换……

前面我们大概了解了JIT的原理,也了解到 JIT 编译后,机器码执行效率更高,那有什么办法能了解到我们自己的应用里,JIT有没有执行,用的是C1还是C2,对哪些代码做过编译和优化呢?

我们有没有办法,能知道都有哪些方法被JIT编译了,哪些方法本来我们想要效率高一些,期待被编译却没被考虑的,能更直观的知道呢?

一个办法是应用启动时,增加 JVM 参数:

  • -XX:+UnlockDiagnosticVMOptions
  • -XX:+PrintCompilation
  • -XX:+PrintInlining
  • -XX:+PrintCodeCache
  • -XX:+PrintCodeCacheOnCompilation
  • -XX:+TraceClassLoading
  • -XX:+LogCompilation
  • -XX:LogFile=~/a.log

然后根据这些输出内容,以及日志文件里的内容,去分析。

当然,如果真的是肉眼阅读那可太累了。好在有一个优秀的开源工具用于解析日志文件。

铛铛铛,来了。

就是它, JITWatch。

(编辑:衡水站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读