最近在做一个项目的性能优化,遇到好多以前没有关注过的性能问题,一头雾水,今天做个笔记,简单记录下JVM相关的参数设置。

一、JVM内存模型

  1. 首先介绍下Java程序具体执行的过程:
  • Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀);
  • 由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行;
  • 在整个程序执行过程中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存;
  • 因此,在Java中我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间)。

  2.  JVM的内存划分和各区域职责:

  

  • 程序计数器:程序计数器是指CPU中的寄存器,它保存的是程序当前执行的指令的地址(也可以说保存下一条指令的所在存储单元的地址),当CPU需要执行指令时,需要从程序计数器中得到当前需要执行的指令所在存储单元的地址,然后根据得到的地址获取到指令,在得到指令之后,程序计数器便自动加1或者根据转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令;(注:JVM中的程序计数器并不像汇编语言中的程序计数器一样是物理概念上的CPU寄存器,但是逻辑作用上是等同的,在JVM中多线程是通过线程轮流切换来获得CPU执行时间的,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。因此,可以这么说,程序计数器是每个线程所私有的)
  • Java栈:Java栈是Java方法执行的内存模型,Java栈中存放的是一个个的栈帧,每个栈帧(包括:局部变量表、操作数栈、运行时常量池(在下文中提到的方法区内)的引用、方法返回地址和一些额外的附加信息)对应一个被调用的方法,当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈;(注:由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰)
  • 本地方法栈:Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的;
  • 堆:Java中的堆是用来存储对象本身的以及数组;
  • 方法区:它与堆一样,是被线程共享的区域,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。(注:在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。)

二、垃圾回收机制

  这里就不再重复,点击链接可跳转到以前的文章。

三、针对分代垃圾回收调整部分参数

      

  JVM内存的系统级的调优主要的目的是减少Minor GC的频率和Full GC的次数,过多的Minor GC和Full GC是会占用很多的系统资源,影响系统的吞吐量。

1.  年轻代分三个区,一个Eden区,两个Survivor区(from和to区),可以通过-XXSurvivorRatio调整比例

    • 作用:默认-XX:SurvivorRatio=8,表示Survivor区与Eden区的大小比值是1:1:8,在MinorGC过程,如果survivor空间不够大,不能够存储所有的从eden空间和from suvivor空间复制过来活动对象,溢出的对象会被复制到old代,溢出迁移到old代,会导致old代的空间快速增长

2.  大部分对象在先在Eden区中申请内存。

    • 作用:可以通过设置-XX:PreTenureSizeThreShold大小,令大于这个值的对象直接保存到年老代,避免在Eden区与Survivor区之间频繁地通过复制算法回收内存

3.  当Eden区满时,无法为新的对象分配内存时,会进行Minor GC对其回收无用对象占用的内存,如果还有存活对象,则将存活的对象复制到Survivor From区(两个中Survivor对称);然后从Eden区存活下来的对象,就会被复制到From,当这个From区满时,此区的存活对象将被复制到To区,接下来Eden区存活下来的对象就会被复制到To区,经历一定的次数Minor GC后,还存活的对象,将被复制“年老区(Tenured)”。

    • 作用:Minor默认15次,可通过-MaxTenuringThreshold参数调整年轻代回收次数,防止对象过早进入年老代,降低年老代溢出的可能性

4.  年轻代和年老代的默认比例为1:2,即年轻代占堆内存的1/3,年老代占2/3,可调整-XX:NewRatio的大小设置年轻和年老的比例。

    • 作用:默认-XX:NewRatio=2,即young:tenured=1:2,适当调整年轻代大小,可以一定层度上较少Full GC出现的概率

四、其余性能调优常用参数设置

  1. -Xms and -Xmx (or: -XX:InitialHeapSize and -XX:MaxHeapSize):指定JVM的初始和最大堆内存大小,两值可以设置相同,以避免每次垃圾回收完成后JVM重新分配内存。
  2. -Xmn:设置年轻代大小。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
  3. -Xss:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
  4. -XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath:让JVM在发生内存溢出时自动的生成堆内存快照(堆内存快照文件有可能很庞大,推荐将堆内存快照生成路径指定到一个拥有足够磁盘空间的地方。)
  5. -XX:OnOutOfMemoryError:当内存溢发生时,我们甚至可以可以执行一些指令,比如发个E-mail通知管理员或者执行一些清理工作($ java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:OnOutOfMemoryError ="sh ~/cleanup.sh" MyApp)
  6. -XX:PermSize and -XX:MaxPermSize:设置永久代大小的初始值和最大值(默认:最小值为物理内存的1/64,最大值为物理内存的1/16,永久代在堆内存中是一块独立的区域,这里设置的永久代大小并不会被包括在使用参数-XX:MaxHeapSize 设置的堆内存大小中)
  7. -XX:PretenureSizeThreshold :令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制

Java内存模型及性能优化的更多相关文章

  1. JVM内存模型和性能优化 转

    JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...

  2. JVM内存模型和性能优化

    JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于数据库锁. 多核并行计算模 ...

  3. jvm-java内存模型与锁优化

    java内存模型与锁优化 参考: https://blog.csdn.net/xiaoxiaoyusheng2012/article/details/53143355 https://blog.csd ...

  4. 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)

    前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...

  5. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  6. 通过实例程序验证与优化谈谈网上很多对于Java DCL的一些误解以及为何要理解Java内存模型

    个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...

  7. JMM(java内存模型)

    What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...

  8. 《深入理解Java内存模型》读书总结

    概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...

  9. Java内存模型深度解析:volatile--转

    原文地址:http://www.codeceo.com/article/java-memory-4.html Volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特 ...

随机推荐

  1. 把代码搬到Git Hub 吧(一)

    作为码农的我们,应该都是知道Git Hub,因为git几乎是码农必备的技能啊,所以就不多介绍Git Hub了,直入主题,这篇博客主要讲解Git Hub网页端和客户端的操作. 网页端: 首页第一步自然是 ...

  2. iOS小知识:计算字符串长度(如果有表情,表情的长度为1)

    在做项目的时候,textField能够输入表情,但是iOS的表情是占两个字符的,再计算字符串长度的时候就和想象的不一样了,所以用了次方法会将表情的长度转成1,最后得到的字符串的长度就是能看到的实际的长 ...

  3. Springsecurity3.1.3配置多个登陆页面

    需求:网站的前台和后台不同的url需要不同的登陆页面,不同的异常捕获方式. spring-security3.1以后的版本支持多个<http>标签,因此本文所采用的方式就是使用两个,实际上 ...

  4. Javascript设计模式学习三(策略模式)

    定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换.目的:将算法的使用和算法的实现分离开来.比如: if(input == 'A'){ return 1; } if(input == ...

  5. GridLayout 使用

    上次做了一个小键盘,请见:PopupWindow 使用. 效果是这样的: 可以看到,上面的按键是不一样大小的.因为是用LinearLayout布局,用的Button样式也是默认的.数字键和文字键的大小 ...

  6. mySQL 中主键值自动增加

    转  http://stevenjohn.iteye.com/blog/976397 MySql 主键自动增长 博客分类: DataBase MySQLSQL  创建数据库,创建表. mysql> ...

  7. bzoj4025 二分图

    支持加边和删边的二分图判定,分治并查集水之(表示我的LCT还很不熟--仅仅停留在极其简单的模板水平). 由于是带权并查集,并且不能路径压缩,所以对权值(到父亲距离的奇偶性)的维护要注意一下. 有一个小 ...

  8. Java关于IO流的介绍

    JDK提供的流继承了四大类:InputStream(字节输入流).OutputStream(字节输出流).Reader(字符输入流).Writer(字符输出流). 字符流和字节流的主要区别:     ...

  9. 【Oracle】Oracle日期格式详解

    本文章没有经过验证,纯属使用CV大法.感谢原创的大牛. to_date("要转换的字符串","转换的格式")   两个参数的格式必须匹配,否则会报错. 即按照第 ...

  10. 将十进制数转为一个n位数的密码(每位都是个m进制数)

    例如一个6位数的10进制密码,共有106个密码,如果把每个6位数的密码编成号就是[0,106-1].这是十进制的情况,即6个位,每个位有10种选择.如果要遍历所有密码,需要6重for循环,每个循环10 ...