原文链接

现在多核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越大,对象可以在年轻态呆更多时间。

多核服务器的JVM优化选项(转载)的更多相关文章

  1. Web服务器Nginx多方位优化策略

    标签:性能 Web 架构 Nginx 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://dongsong.blog.51cto.co ...

  2. 性能优化系列三:JVM优化

    一.几个基本概念 GCRoots对象都有哪些 所有正在运行的线程的栈上的引用变量.所有的全局变量.所有ClassLoader... 1.System Class.2.JNI Local3.JNI Gl ...

  3. Java虚拟机内存基础、垃圾收集算法及JVM优化

    1 JVM 简单结构图   1.1 类加载子系统与方法区 类加载子系统负责从文件系统或者网络中加载 Class 信息,加载的类信息存放于一块称 为方法区的内存空间.除了类的信息外,方法区中可能还会存放 ...

  4. gcc 优化选项 -O1 -O2 -O3 -Os 优先级

    http://hi.baidu.com/xiaole10368/item/7cea9b1369cc240db88a1a5c 少优化->多优化: O0 -->> O1 -->&g ...

  5. JVM优化

    1.堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...

  6. JVM虚拟机选项:Xms Xmx PermSize MaxPermSize区别(转)

    java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制.否则可能导致应用程序宕掉. 举例说明含义:-Xms128m表示JVM Heap(堆内存)最小尺寸128MB,初 ...

  7. linux下jvm优化、tomcat调优

    系统环境:jdk1.8,apache-tomcat-8.5.35 一.jvm优化 进入 bin/catalina.sh,修改JAVA_OPTS配置: JAVA_OPTS="-server - ...

  8. 简单的jvm优化的尝试

    一.eclipse 启动优化 在日常的开发中发现eclipse 启动的时候非常慢,并且在实际的开发中也非常卡,所以尝试着优化一下.现在eclipse 是运行在jdk1.7上. 首先我们可以看到ecli ...

  9. 系统优化怎么做-JVM优化之VisualVM

    大家好,这里是「聊聊系统优化 」,并在下列地址同步更新 博客园:http://www.cnblogs.com/changsong/ 知乎专栏:https://zhuanlan.zhihu.com/yo ...

随机推荐

  1. Docker工具

    虚拟化 什么是虚拟化 在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源, 如服务器.网络.内存及存储等,予以抽象.转换后呈现出来, 打破实体结构间的 ...

  2. QT添加自定义信号后编译出现undefined reference

    QT添加自定义信号后编译出现undefined reference 这是需要重新生成qmake: build --->run qmake

  3. centos7 安全配置

    CentOS是最多人用来运行服务器的 Linux 版本,最新版本是 CentOS 7.当你兴趣勃勃地在一台主机或 VPS 上安装 CentOS 7 后,首要的工作肯定是加强它的安全性,以下列出的七件事 ...

  4. uncaught exception 'NSInternalInconsistencyException, reason:[UITableViewController loadView] loaded the "Controller" nib but didn't get a UITableView

    http://blog.csdn.net/ryantang03/article/details/7941058#reply 上面那篇文章是我查找的ios实现下拉刷新功能,在我下载完代码运行的过程中发现 ...

  5. Hydux: 一个 Elm-like 的 全功能的 Redux 替代品

    在学习和使用 Fable + Elmish 一段时间之后,对 Elm 架构有了更具体的了解, 和预料中的一样,Redux 这种来自 Elm 的风格果然还是和强类型的 Meta Language 语言更 ...

  6. Selenium WebDriver- 操作JavaScript的prompt弹窗(使用率低)

    #encoding=utf-8 import unittest import time from selenium import webdriver from selenium.webdriver i ...

  7. Xpath - Xpath定位

     selenium 提供的xpath定位方法名为:find_element_by_xpath(xpath表达式) Xpath基本定位语法: / 绝对定位,从根节点选取 // 相对定位,从匹配选择的当前 ...

  8. python + selenium - selenium简介

    1. 产品简介 selenium 是 基于 web网页的UI自动化测试框架. 1)支持多浏览器操作:ie.chrome.firefox.edge.safaria等 2)跨平台:windows.linu ...

  9. jmeter返回的Unicode转换成utf8

    该问题通过查找资料借鉴前辈门的经验得到了解决,记录下来是为了后面能够用到 最近发现有些接口返回的时unicode类型的,如下图所示: 因此只需要在jmeter中添加后置处理器:BeanShell Po ...

  10. day04_07 while循环01

    while循环结构: #while 条件: print("any") print("any") 死循环案例 num = 1 while num<=10 : ...