JVM源碼分析之System.currentTimeMillis及nanoTime原理詳解 PerfMa

本文來自PerfMa技術社區:club.perfma.comlinux

PerfMa(笨馬網絡)官網:www.perfma.commacos

概述

上週有同事問了我一個現象很詭異的問題,說JDK7和JDK8下的System.nanoTime()輸出徹底不同,並且差距還很是大,是否是兩個版本里的實現不同,以前我也沒注意過這個細節,以爲很是奇怪,因而本身也在本地mac機器上立刻測試了一下,獲得以下輸出:網絡

image.png

還真不同,因而我再到linux下跑了一把,發現兩個版本下的值基本上差很少的,也就是主要是mac下的實現可能不同架構

因而我又調用System.currentTimeMillis(),發現其輸出結果和System.nanoTime()也徹底不是1000000倍的比例分佈式

image.png

另外System.nanoTime()輸出的究竟是什麼東西,這個數字好奇怪函數

這三個小細節平時沒有留意,好奇心做祟,因而立刻想一查究竟測試

再列下主要想理清楚的三個問題code

  • 在mac下發現System.nanoTime()在JDK7和JDK8下輸出的值怎麼徹底不同cdn

  • System.nanoTime()的值很奇怪,到底是怎麼算出來的blog

  • 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倍左右了,由於兩個值的參照不同,因此沒有可比性

推薦閱讀

世界最優秀的分佈式文件系統架構演進之路

一次百萬長鏈接壓測 Nginx OOM 的問題排查分析

相關文章
相關標籤/搜索