现在多核CPU是主流。利用多核技术,可以有效发挥硬件的能力,提升吞吐量,对于Java程序,可以实现并发垃圾收集。但是Java利用多核技术也带来了一些问题,主要是多线程共享内存引起了。目前内存和CPU之间的带宽是一个主要瓶颈,每个核可以独享一部分高速缓存,可以提高性能。JVM是利用操作系统的"轻量级进程"实现线程,所以线程每操作一次共享内存,都无法在高速缓存中命中,是一次开销较大的系统调用。所以区别于普通的优化,针对多核平台,需要进行一些特殊的优化。
代码优化
线程数要大于等于核数
如果使用多线程,只有运行的线程数比核数大,才有可能榨干CPU资源,否则会有若干核闲置。要注意的是,如果线程数目太多,就会占用过多内存,导致性能不升反降。JVM的垃圾回收也是需要线程的,所以这里的线程数包含JVM自己的线程
尽量减少共享数据写操作
每个线程有自己的工作内存,在这个区域内,系统可以毫无顾忌的优化,如果去读共享内存区域,性能也不会下降。但是一旦线程想写共享内存(使用volatile关键字),就会插入很多内存屏障操作(Memory Barrier或者Memory Fence)指令,保证处理器不乱序执行。相比写本地线程自有的变量,性能下降很多。处理方法是尽量减少共享数据,这样也符合"数据耦合"的设计原则。
使用synchronize关键字
在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。
使用乐观策略
传统的同步并发策略是悲观的。表现语义为:多线程操作一个对象的时候,总觉得会有两个线程在同时操作,所以需要锁起来。乐观策略是,假设平时就一个线程访问,当出现了冲突的时候,再重试。这样更高效一些。Java的AtomicInteger就是使用了这个策略。
使用线程本地变量(ThreadLocal)
使用ThreadLocal可以生成线程本地对象的副本,不会和其他线程共享。当该线程终止的时候,其本地变量可以全部回收。
类中Field的排序
可以将一个类会频繁访问到的几个field放在一起,这样他们就有更多的可能性被一起加入高速缓存。同时最好把他们放在头部。基本变量和引用变量不要交错排放。
批量处理数组
现在处理器可以用一条指令来处理一个数组中的多条记录,例如可以同时向一个byte数组中读或者写store记录。所以要尽量使用System.arraycopy()这样的批量接口,而不是自己操作数组。
JVM优化
启用大内存页
现在一个操作系统默认页是4K。如果你的heap是4GB,就意味着要执行1024*1024次分配操作。所以最好能把页调大。这个配额设计操作系统,单改Jvm是不行的。Linux上的配置有点复杂,不详述。
在Java1.6中UseLargePages是默认开启的,LasrgePageSzieInBytes被设置成了4M。笔者看到一些情况下配置成了128MB,在官方的性能测试中更是配置到256MB。
启用压缩指针
Java的64的性能比32慢,原因是因为其指针由32位扩展到64位,虽然寻址空间从4GB扩大到256 TB,但导致性能的下降,并占用了更多的内存。所以对指针进行压缩。压缩后的指针最多支持32GB内存,并且可以获得32位JVM的性能。
在JDK6 update 23默认开启了,之前的版本可以使用-XX:+UseCompressedOops来启动配置。
性能可以看这个评测,性能的提升是很可观。
启用NUMA
numa是一个CPU的特性。SMP架构下,CPU的核是对称,但是他们共享一条系统总线。所以CPU多了,总线就会成为瓶颈。在NUMA架构下,若干CPU组成一个组,组之间有点对点的通讯,相互独立。启动它可以提高性能。
NUMA需要硬件,操作系统,JVM同时启用,才能启用。Linux可以用numactl来配置numa,JVM通过-XX:+UseNUMA来启用。
激进优化特性
在Java1.6中,激进优化(AggressiveOpts)是默认开启的。激进优化是一般有一些下一个版本才会发布的优化选项。但是有可能造成不稳定。前段时间以讹传讹的JDK7的Bug,就是开启这个选项后测到的。
逃逸分析
让一个对象在一个方法内创建后,如果他传递出去,就可以称为方法逃逸;如果传递到别的线程,成为线程逃逸。如果能知道一个对象没有逃逸,就可以把它分配在栈而不是堆上,节约GC的时间。同时可以将这个对象拆散,直接使用其成员变量,有利于利用高速缓存。如果一个对象没有线程逃逸,就可以取消其中一切同步操作,很大的提高性能。
但是逃逸分析是很有难度的,因为花了cpu去对一个对象去分析,要是他不逃逸,就无法优化,之前的分析血本无归。所以不能使用复杂的算法,同时现在的JVM也没有实现栈上分配。所以开启之后,性能也可能下降。
可以使用-XX:+DoEscapeAnalysis来开启逃逸分析。
高吞吐量GC配置
对于高吞吐量,在年轻态可以使用Parallel Scavenge,年老态可以使用Parallel Old垃圾收集器。
使用-XX:+UseParallelOldGC开启
可以将-XX:ParallelGCThreads根据CPU的个数进行调整。可以是CPU数的1/2或者5/8
低延迟GC配置
对于低延迟的应用,在年轻态可以使用ParNew,年老态可以使用CMS垃圾收集器。
可以使用-XX:+UseConcMarkSweepGC和-XX:+UseParNewGC打开。
可以将-XX:ParallelGCThreads根据CPU的个数进行调整。可以是CPU数的1/2或者5/8
可以调整-XX:MaxTenuringThreshold(晋升年老代年龄)调高,默认是15.这样可以减少年老代GC的压力
可以-XX:TargetSurvivorRatio,调整Survivor的占用比率。默认50%.调高可以提供Survivor区的利用率
可以调整-XX:SurvivorRatio,调整Eden和Survivor的比重。默认是8。这个比重越小,Survivor越大,对象可以在年轻态呆更多时间。
等等
参见:《Java优化白皮书》,《深入理解Java虚拟机》
相关推荐
Projeto-Infotec:Nós,Alunos do Curso技术信息,Jogo 2D开发,degênero悬念,enviralado numa escola,utilizando和Java语言的编程语言,以及Java播放器
JDK版本支持 -- 1.8或以上
ca原始Java 欢迎使用Card Raytracer基准测试。 我们的目标: 将“ ...NUMA个节点: 1个 供应商ID: 正品AMD CPU系列: 23 模型: 1个 型号名称: AMD锐龙5 1600六核处理器 步进: 1个 CPU MHz: 137
matrices.txt 文件:将 GetMatrices.java 中第 32 行的路径更改为该文件放置在 matrices.txt 包含矩阵的当前路径。 此文件具有以下格式,如果修改此文件,则应遵循此格式。 读取时忽略此文件的第一行。 第一行之后...
java8流源码穿山甲 分支 地位 掌握 用于 GPU 图形操作的仅标头 C++/CUDA 库。 . 入门 安装 CUDA 大多数穿山甲只适用于nvcc 。 安装 NUMA(可选) sudo apt install libnuma-dev 在您的代码中包含穿山甲头文件,并在...
Java办公OA管理系统源码缩写变量名对照表 简称 全名 普遍的 ----- CEP 复杂事件处理 重庆 更改数据捕获 目录 关系数据库服务 WASM WebAssembly 顶级域名 顶级域名 实时出价 实时竞价 RTA 实时接口 访问控制列表 访问...
SMP和NUMA有什么区别? 这如何影响程序? Multicore和Multisocket有什么区别? 什么是线程关联性? 我可以用Java做到吗? 什么是线程间并行性? 任务并行性? 什么是分支预测? 什么是投机执行? 从程序员的...
版本包含的 JEP(Java/JDK Enhancement Proposals,JDK 增强提案)比 Java 12 和 13 加起来的还要多。总共 16 个新特性如下: 305:Pattern Matching for instanceof (Preview) 为 instanceof 运算符引入模式...
OSHI是Java的免费的基于JNA的(本机)操作系统和硬件信息库。 它不需要安装任何其他本机库,并且旨在提供一种跨平台的实现来检索系统信息,例如OS版本,进程,内存和CPU使用率,磁盘和分区,设备,传感器等。 支持...
它已并行化,可以在多核处理器和NUMA架构上轻松高效地使用(使用libnuma本机库)。 它主要针对密集相似矩阵。 除了基本的(并行)算法之外,它还实现了层次的亲和力传播(HiAP),即使在庞大的数据集上也可以在实践...
## :bookmark: 列出成为完整Syack Java Jr开发人员的...# Entrar numa IDE de sua preferência # Executar o servidor ou usar um puglin que criar um servidor :thinking_face: 如何贡献 分叉此存储库; 使用您
1、移除 Java DB(Apache Derby) 2、改进 LDAP 支持 3、更好的 stack walking 4、修复无法在 JDK 8 中使用 JDWP API 来调试 JDK>= 9 的问题 5、修复 JVM 在 G1 GC 期间崩溃的问题 6、引入较旧的 NUMA 库(-XX + ...
方法一: 使用循环加switch判断加计数变量 public static void main(String[] args){ ... int numA = 0; int numE = 0; int numI = 0; int numO = 0; int numU = 0; while ((len = in.read(buffer)) != -1){
本章主要介绍在数据库、大数据和HPC场景下进行性能测试的方法,使用华为鲲鹏性能优化工具Kunpeng Tuning Kit对C/C++类程序和Java Mixed-Mode类程序进行性能分析的方法,以及对NUMA和线程并发数进行性能调优的案例。
更别提内容涉及Microservices、Kubernetes、SOA、Distribute Memory、ElasticSearch、Kafka、CAP、NUMA、SOA、GlusterFS、Actor、Akka、RabbitMQ、Spring Cloud、ZeroC Ice…… Leader-us的文字还是那样充满IT...
1、onclick是鼠标单击事件,当在网页上单击鼠标... var numa,numb,sum; numa=6; numb=8; sum=numa+numb; [removed](两数和为:+sum); } [removed] </head> <body> <form> <input name=butt
支持MIC硬件,NUMA和实时网络内存以及完整的IPv6。 最终的Alpha版本功能:======== * USB图像*常规debian存储库*虚拟机优化*默认情况下为大页面*默认情况下为CGROUP优化* ALSA *最新调试/ Baremetal内核*测试中具有...
代码如下: [removed] var test = { numA: 10, objB: {}, arrC: [], init: function(){ alert(this.numA); }, sayHi: function(name){ alert(“hello ” + name); }, sayHelloWorld: function(){ ...
Synchrobench用C / C ++和Java编写,目前包括与写入时复制,锁定,读取-修改-写入,读取-复制-更新同步的数组,二进制树,哈希表,链接列表,队列和跳过列表。和事务性内存。 每种语言都提出了这些数据结构的非同步...
Python中的浮点类型类似Java语言中的double 类型,是双精度浮点型,可以直接用十进制或科学计数法表示。十进制数形式,由数字和小数点组成,且必须有小数点,如123.332等;科学计数法形式,如:2.1E5、