现在多核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虚拟机》
相关推荐
在多处理器环境中,非统一内存访问(NUMA)架构、硬件共享内存、内存栅栏和CPU缓存等都是影响并发性能的因素。 13. Java并发编程展望 摩尔定律是衡量硬件发展速度的重要指标,它预言了处理器性能的增长趋势。Java...
Duas instruções sem um ponto-e-vírgula entre elasUma palavra-chave sendo usada numa posição inesperada。语义错误如果错误是“逻辑逻辑”,则该语义是正确的,但我们无法理解。Tentar dividir um número...
NUMA化数据结构支持高性能。 Paxos一致性日志复制协议,主备模式,CRC校验支持高可用。 支持全密态计算、账本数据库等安全特性,提供全方位端到端的数据安全保护。 通过Table Access Method接口层支持多存储引擎。
我们将探讨由多核平台带来的挑战,包括AMD/Intel与UltraSPARC平台、基于非统一内存访问(NUMA)的平台以及UltraSPARC/CMT Sun Fire T1000/T2000平台。 #### 针对多核平台调优JVM 为了充分发挥多核处理器的优势,我们...
在JAVA11的培训课程中,我们关注了两个重要的大数字操作类——BigInteger和BigDecimal,它们都位于`java.math`包中,用于处理超过普通整型和浮点型所能表示的大数字。 首先,BigInteger类是Java提供的无符号整数类...
"关爱通开放平台SDK-JAVA版"是一款专为Java开发者设计的工具,旨在帮助开发者轻松地与关爱通的开放平台进行交互,实现各种业务功能。这个SDK是基于JDK 1.8或更高版本构建的,确保了它能兼容最新的Java技术和特性,以...
在本项目"Projeto-Infotec"中,一组技术信息课程的学生们开发了一款2D悬疑游戏,这个游戏设定在一个学校环境中,并通过Java编程语言实现。这个项目突显了Java在游戏开发领域的应用,尤其是2D游戏制作。下面将详细...
还有两个`Double`类型的变量`numA`和`numB`,用于存储运算中的两个数字,以及一个`operFlag`用于记录当前操作的类型(加、减、乘、除)。`clearFlag`用于标记是否需要清除当前显示的数值。 `Caculator`构造函数是...
ca原始Java 欢迎使用Card Raytracer基准测试。 我们的目标: 将“ ...NUMA个节点: 1个 供应商ID: 正品AMD CPU系列: 23 模型: 1个 型号名称: AMD锐龙5 1600六核处理器 步进: 1个 CPU MHz: 137
java8流源码穿山甲 分支 地位 掌握 用于 GPU 图形操作的仅标头 C++/CUDA 库。 . 入门 安装 CUDA 大多数穿山甲只适用于nvcc 。 安装 NUMA(可选) sudo apt install libnuma-dev 在您的代码中包含穿山甲头文件,并在...
matrices.txt 文件:将 GetMatrices.java 中第 32 行的路径更改为该文件放置在 matrices.txt 包含矩阵的当前路径。 此文件具有以下格式,如果修改此文件,则应遵循此格式。 读取时忽略此文件的第一行。 第一行之后...
JSP(Java Server Pages)是一种基于Java技术的服务器端网页编程技术,用于创建动态、交互式的Web应用程序。它允许在HTML或XML文档中嵌入Java代码,这些代码由Web容器中的JSP引擎编译和执行,然后将生成的完整页面...
在Java编程语言中,`==` 和 `equals()` 是两种常用的比较操作符,但它们的用法和含义有所不同。本文将深入探讨这两个概念,并通过实际的代码示例进行测试和解释。 首先,`==` 操作符用于基本类型(如 int、char、...
通过遍历所有可能的因子,如果发现存在与`numA`因子分解不冲突的情况,说明`numA`可能说谎,此时返回`numB`作为胜者。否则,如果遍历完成后没有找到冲突,说明`numA`说了真话,返回`numA`。 `canDivid`方法是一个...
Java办公OA管理系统源码缩写变量名对照表 简称 全名 普遍的 ----- CEP 复杂事件处理 重庆 更改数据捕获 目录 关系数据库服务 WASM WebAssembly 顶级域名 顶级域名 实时出价 实时竞价 RTA 实时接口 访问控制列表 访问...
### 软件设计之工厂方法模式解析及Java实现 #### 一、工厂方法模式概述 工厂方法模式(Factory Method Pattern)是一种常用的面向对象设计模式,属于创建型模式之一。它提供了一种创建对象的最佳方式。在工厂方法...
3. **NUMA-Aware Memory Allocation for G1** - G1垃圾收集器得到了优化,能够更好地处理NUMA(Non-Uniform Memory Access)架构,提高了内存分配效率,降低CPU的内存访问延迟。 4. **JFR Event Streaming** - Java...
Java静态内部类详解 Java中的内部类是指在一个类中定义的另一个类,它可以帮助我们更好地组织代码,使代码更加简洁和易于维护。在Java中,内部类可以分为静态内部类和非静态内部类两种。本文将主要介绍Java静态内部...