用来运行Java语言的HotSpot VM主要是用C++语言来写的,所以我们在研究JDK时不得不去学习C++这门语言。C++和Java都是面向对象的语言,所以它们常被拿来做比较。本文将从性能的角度对比分析 Java 和 C++,粗略探讨两者在峰值速度、启动时间和启动性能以及内存利用率方面的差异。

## 1、峰值速度

Java的C2编译器能结合运行时的信息做推断和激进优化,其峰值性能并不比C++差。

C++有接近硬件的操作能力、执行效率和低级控制在性能要求极高的领域中占据一席之地。

所以两者并不能笼统的脱离实际来说性能的高低。不过我们倒是可以列举一些影响峰值速度的点来探讨。

### (1)内联

Java无论是C1还是C2编译器,内联都是重点的优化手段之一。Java类是动态加载的,HotSpot VM可以对这些新加载进来的类进行内联优化。不过目前的Java会在运行时调用native,在某些必要的情况下还会调用HotSpot VM内部的函数,这些是没办法内联的,这也是native开销大的原因之一。所以用纯Java写的一些算法也未必比调用native方法慢,比如在JDK8中并不支持Vector API,所以需要通过native来使用本地的向量化指令,但通过native调用时开销绝对不可以忽视。

Project Panama 的目标之一是

通过提供新的API来减少 JNI(Java Native Interface)的使用。

对于C++来说,动态链接库之间不能进行函数内联,否则就没办法让动态链接库单独进行更新和升级。另外动态分派中可被内联的情况也比较少。

### (2)动态分派

Java默认的方法都是动态分派,而C++需要通过virtual关键字专门指定,所以Java代码中的虚方法应该比C++中的多很多才对。

HotSpot VM中的虚函数能获取的信息更多,所以优化的手段也比较多,例如通过C2对receiver的类型推导、CHA(类型继承关系分析)以及运行时对receiver的type profile,这些可能让Java方法做单态内联、双态内联、多态内联、守护内联或做内联缓存优化。

C++是纯编译语言,虽然也有一些手段对虚函数做内联,但比起Java来,可用的内联信息更少,所以内联的效果肯定不如Java好。

### (3)值类型

Java不支持值类型,而C++支持。Java采用的是托管机制,其运行时动态编译编译和自动内存管理极大的降低了Java使用的门槛,不过Java不建议对底层的内存进行直接操作,所以也无法对底层的内存布局进行操作。有人将这称为导致Java和C语言之间性能差距的最后一个主要障碍。

当我们使用容器时,这种无值类型导致的性能差距可能更加明显,目前Java容器中的数组、链表不能直接保存结构,必须保存引用。所以Java数据结构和STL容器没法比。不过Java可以进行逃逸分析和标量替换,把许多临时对象的内存分配到栈上,这在一定程序上弥补了没有值类型的短板。

### (4)额外开销

HotSpot VM的托管技术让它有许多额外的开销,如GC和编译开销。在程序运行起来后,一切GC和编译相关的问题都是Java特有的,C++并不存在这种问题。

Java有许多额外检查,比如GC安全点检查、内存越界检查、类型检查等,这是我们为托管技术和安全性付出的必要代价。

Java中每个基本类型都有对应的包装类,这在一些上下文中需要频繁进行装箱和拆箱操作,C++并不存在这种问题。

总的来说,C++由于可操控性太强,只要代码写的足够好,额外开销是非常少的。对于Java来说,我们不得不做很多的让步。

## 2、启动时间和启动性能

Java虚拟机的动态特性让它可以根据需要对类进行加载。Java是面向对象的语言(Slogan:everything is object),类数量通常比较大且类加载还是IO操作,严重拖累了Java的启动速度,目前主要是通过CDS(后序的AppCDS、Dynamic CDS)来解决。

HotSpot VM为了照顾启动和峰值性能,默认采用的是分层编译,所以需要在系统运行一段时间后才能逐步由解释执行转化为解释执行 + 编译执行,这也意味着系统需要经过一段时间的预热才能达到性能巅峰

C++ 是静态编译的语言,代码在编译时直接生成机器码,启动即巅峰,其启动时间和启动性能应该要完胜Java才对。

不过随着云原生的到来,Java的启动时间慢和启动性能低的缺点被放大,Java开发者也在努力解决这些问题。例如:

(1)通过CDS来优化类加载的速度,这样可以显著减少类加载、解析和初始化的时间

(2)JDK 9开始提供工具jaotc,同时GraalVM的Native Image都是可以通过静态编译,极大地提升服务的启动速度的方式

(3)CRaC(协调恢复检查点)可以把预热后的 JVM 保存下来,然后快速启动。也就是快照保存和恢复。

更多的启动相关的优化可以看看Project Leyden项目,这个项目专注于缩短 Java 应用程序的启动时间。

另外,Azul JDK的Platform Prime版本提供了Ready Now和Ready Now Orchestrator作为解决 Java 预热问题的解决方案,阿里也在启动上做了一些优化和探索。

## 3、内存利用率

之前我写过 “历数Java虚拟机GC的种种缺点" 文章,文章中提到过额外分配和浪费的内存,如To Survivor不能用来进行内存分配,卡表需要额外的内存,Java的延迟回收让它白白点用了一段时间内存。

C++具有接近硬件的操作能力,以HotSpot VM为例,它通过重载new和delete运算符、通过C++中的资源获取即初始化技术将资源的分配和释放与对象的生命周期进行绑定等手段,实现了对内存的精确控制。

由于Java对内存的利用率低,所以和C++相比,它的峰值内存和平时内存占用都会显著高于C++程序。

Java的物理内存归还,Lilliput缩小Java对象头、CDS让多个虚拟机共享类元数据以及Valhalla项目对Java值类型的支持,都能够提高Java内存的利用率,减少浪费。

更多文章可访问:[JDK源码剖析网](http://hotspotvm.cn)

<img src="https://img2024.cnblogs.com/blog/1236123/202504/1236123-20250424100503675-351126910.png" width="550" height="200">

Java和C++性能大比拼的更多相关文章

  1. lua、groovy嵌入到java中的性能对比(转)

    lua和groovy都是可以嵌入到java中的脚本语言.lua以高性能著称,与C/C++在游戏开放中有较多使用,groovy是一个基于Java虚拟机(JVM)的敏捷动态语言,在jvm下有着不错的性能. ...

  2. 2017年的golang、python、php、c++、c、java、Nodejs性能对比(golang python php c++ java Nodejs Performance)

    2017年的golang.python.php.c++.c.java.Nodejs性能对比 本人在PHP/C++/Go/Py时,突发奇想,想把最近主流的编程语言性能作个简单的比较, 至于怎么比,还是不 ...

  3. 性能调优之Java系统级性能监控及优化

    性能调优之Java系统级性能监控及优化   对于性能调优而言,通常我们需要经过以下三个步骤:1,性能监控:2,性能剖析:3,性能调优 性能调优:通过分析影响Application性能问题根源,进行优化 ...

  4. 2017年的golang、python、php、c++、c、java、Nodejs性能对比[续]

    2017年的golang.python.php.c++.c.java.Nodejs性能对比[续] 最近忙,这个话题放了几天,今天来个续集.   上篇传送门: 2017年的golang.python.p ...

  5. Java应用常用性能分析工具

    Java应用常用性能分析工具 好的工具有能有效改善和提高工作效率或加速分析问题的进度,笔者将从事Java工作中常用的性能工具和大家分享下,如果感觉有用记得投一票哦,如果你有好的工具也可以分享给我 工具 ...

  6. JProfiler 解决 Java 服务器的性能跟踪

    作者:徐建祥(netpirate@gmail.com) 时间: 2006/01/05 来自:http://www.anymobile.org 1.摘要......................... ...

  7. 用于快速排查Java的CPU性能问题(top us值过高)

    转载于GIT路径 https://github.com/oldratlee/useful-scripts/blob/master/docs/java.md#beer-show-busy-java-th ...

  8. Java-Runoob-高级教程-实例-字符串:11. Java 实例 - 字符串性能比较测试

    ylbtech-Java-Runoob-高级教程-实例-字符串:11. Java 实例 - 字符串性能比较测试 1.返回顶部 1. Java 实例 - 字符串性能比较测试  Java 实例 以下实例演 ...

  9. Java MVC框架性能比较

    Java MVC框架性能比较 - by zvane 现在各种MVC框架很多,各框架的优缺点网络上也有很多的参考文章,但介绍各框架性能方面差别的文章却不多,本人在项目开发中,感觉到采用了struts2框 ...

  10. 使用Memcached改进Java企业级应用性能:架构和设置

    Memcached由Danga Interactive开发.用来提升LiveJournal.com站点性能. Memcached分布式架构支持众多的社交网络应用,Twitter.Facebook还有W ...

随机推荐

  1. Linux介绍及使用(1)

    一.linux介绍 1.Linux是一个免费.开源的操作系统,能多用户.多任务.支持多线程和多CPU的操作系统,相对windows更加稳定,在unix系统的基础上开发的系统: 注解:(1)免费:不要钱 ...

  2. 发那科机器人R2000iC齿轮箱维修方法步骤归纳

    一.发那科机器人R2000iC齿轮箱常见故障类型及原因 齿轮磨损:长时间的重载工作或润滑不良可能导致齿轮磨损,表现为噪音增大.振动加剧等. 轴承故障:轴承承受了齿轮箱的径向和轴向载荷,其故障可能导致齿 ...

  3. docker - [08] Portainer可视化面板安装

    Docker图形化界面管理工具 一.运行容器 同时下载和使用镜像运行容器 docker run -d -p 8088:9000 \ --restart=always -v /var/run/docke ...

  4. SpringMVC - 谈谈你对SpringMVC的理解

    谈谈你对 Spring MVC 的理解? 普通人:Spring MVC 它是一个MVC框架吧,就是,我们可以使用Spring MVC来开发Web应用...呃 它是基于Servlet上的一个扩展,就是它 ...

  5. git 命令手册【不定时更新】

    本地分支 --> 远程服务器 git add xxx git commit -m "xxx" git push origin xxx 远程服务器 --> 本地分支 gi ...

  6. 带大家做了个 AI 项目,没想到这么简单!

    大家好,我是程序员鱼皮,现在已经是全民 AI 时代了,咱们程序员更要想办法榨干 AI,把 AI 利用起来.前几天我一时兴起,直播用 2 多个小时的时间,从需求分析开始,带大家做了一个 AI 海龟汤游戏 ...

  7. vscode如何退出/切换 github 账号

    退出/切换 github 账号 左下角点击头像按钮,选择注销,然后再重新登录

  8. The selected directory is not a valid home for Go SDK

    前言 The selected directory is not a valid home for Go SDK 出现这个错误的原因是 idea 的 Go-plugin 插件,和 Go 的sdk版本不 ...

  9. 归并排序(递归)(NB)

    博客地址:https://www.cnblogs.com/zylyehuo/ 递归思路 # _*_coding:utf-8_*_ import random def merge(li, low, mi ...

  10. 什么是 IPv6,为什么我们还未普及?

    在大多数情况下,已经没有人一再对互联网地址耗尽的可怕境况发出警告,因为,从互联网协议版本 4(IPv4)的世界到 IPv6 的迁移,虽然缓慢,但已经坚定地开始了,并且相关软件已经到位,以防止许多人预测 ...