性能文章>JVM源码分析之System.currentTimeMillis及nanoTime原理详解>

JVM源码分析之System.currentTimeMillis及nanoTime原理详解原创

2年前
807219

概述

上周有同事问了我一个现象很诡异的问题,说JDK7和JDK8下的System.nanoTime()输出完全不一样,而且差距还非常大,是不是两个版本里的实现不一样,之前我也没注意过这个细节,觉得非常奇怪,于是自己也在本地mac机器上马上测试了一下,得到如下输出:

image.png

还真不一样,于是我再到linux下跑了一把,发现两个版本下的值基本上差不多的,也就是主要是mac下的实现可能不一样

于是我又调用System.currentTimeMillis(),发现其输出结果和System.nanoTime()也完全不是1000000倍的比例

image.png

另外System.nanoTime()输出的到底是什么东西,这个数字好奇怪

这三个小细节平时没有留意,好奇心作祟,于是马上想一查究竟

再列下主要想理清楚的三个问题

  • 在mac下发现System.nanoTime()在JDK7和JDK8下输出的值怎么完全不一样

  • System.nanoTime()的值很奇怪,究竟是怎么算出来的

  • System.currentTimeMillis()为何不是System.nanoTime()的1000000倍

MAC不同JDK版本下nanoTime实现异同

在mac下,首先看JDK7的nanoTime实现

image.png

再来看JDK8下的实现

image.png

果然发现JDK8下多了一个__APPLE__宏下定义的实现,和JDK7及之前的版本的实现是不一样的,不过其他BSD系统是一样的,只是macos有点不一样,因为平时咱们主要使用的环境还是Linux为主,因此对于macos下具体异同就不做过多解释了,有兴趣的自己去研究一下。

Linux下nanoTime的实现

在linux下JDK7和JDK8的实现都是一样的

image.png

而Linux::supports_monotonic_clock决定了走哪个具体的分支

image.png

_clock_gettime的定义在

image.png

说白了,其实就是看librt.so.1或者librt.so中是否定义了clock_gettime函数,如果定义了,就直接调用这个函数来获取时间,注意下上面的传给clock_gettime的一个参数是CLOCK_MONOTONIC,至于这个参数的作用后面会说,这个函数在glibc中有定义

image.png

而对应的宏SYSDEP_GETTIME定义如下:

image.png

最终是调用的clock_gettime系统调用:

image.png

而我们JVM里取纳秒数时传入的是CLOCK_MONOTONIC这个参数,因此会调用如下的方法

image.png

上面的wall_to_monotonic的tv_sec以及tv_nsec都是负数,在系统启动初始化的时候设置,记录了启动的时间

image.png

因此nanoTime其实算出来的是一个相对的时间,相对于系统启动的时候的时间

Java里currentTimeMillis的实现

我们其实可以写一个简单的例子从侧面来验证currentTimeMillis返回的到底是什么值

image.png

你将看到输出结果会是两个一样的值,这说明了什么?我们上一篇文章里已经提到了new Date(0).getTime()其实是就是1970/01/01 08:00:00,而new Date().getTime()是返回的当前时间,两个日期一减,其实就是当前时间距离1970/01/01 08:00:00有多少毫秒,而System.currentTimeMillis()返回的正好是这个值,也就是说System.currentTimeMillis()就是返回的当前时间距离1970/01/01 08:00:00的毫秒数。

就实现上来说,currentTimeMillis其实是通过gettimeofday来实现的

image.png

至此应该大家也清楚了,为什么currentTimeMillis返回的值并不是nanoTime返回的值的1000000倍左右了,因为两个值的参照不一样,所以没有可比性

点赞收藏
分类:标签:
你假笨

通过创新的技术肯定可以让这个世界变得更美好,让我们为技术而狂吧

请先登录,查看1条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

记一次线上RPC超时故障排查及后续GC调优思路

记一次线上RPC超时故障排查及后续GC调优思路

解读JVM级别本地缓存Caffeine青出于蓝的要诀 —— 缘何会更强、如何去上手

解读JVM级别本地缓存Caffeine青出于蓝的要诀 —— 缘何会更强、如何去上手

【全网首发】一次疑似 JVM Native 内存泄露的问题分析

【全网首发】一次疑似 JVM Native 内存泄露的问题分析

解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式

解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式

【全网首发】从源码角度分析一次诡异的类被加载问题

【全网首发】从源码角度分析一次诡异的类被加载问题

9
1