Java内存模型及性能优化
最近在做一个项目的性能优化,遇到好多以前没有关注过的性能问题,一头雾水,今天做个笔记,简单记录下JVM相关的参数设置。
一、JVM内存模型
- 首先介绍下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出现的概率
四、其余性能调优常用参数设置
- -Xms and -Xmx (or: -XX:InitialHeapSize and -XX:MaxHeapSize):指定JVM的初始和最大堆内存大小,两值可以设置相同,以避免每次垃圾回收完成后JVM重新分配内存。
- -Xmn:设置年轻代大小。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
- -Xss:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
- -XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath:让JVM在发生内存溢出时自动的生成堆内存快照(堆内存快照文件有可能很庞大,推荐将堆内存快照生成路径指定到一个拥有足够磁盘空间的地方。)
- -XX:OnOutOfMemoryError:当内存溢发生时,我们甚至可以可以执行一些指令,比如发个E-mail通知管理员或者执行一些清理工作($ java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:OnOutOfMemoryError ="sh ~/cleanup.sh" MyApp)
- -XX:PermSize and -XX:MaxPermSize:设置永久代大小的初始值和最大值(默认:最小值为物理内存的1/64,最大值为物理内存的1/16,永久代在堆内存中是一块独立的区域,这里设置的永久代大小并不会被包括在使用参数-XX:MaxHeapSize 设置的堆内存大小中)
- -XX:PretenureSizeThreshold :令大于这个设置值的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制
Java内存模型及性能优化的更多相关文章
- JVM内存模型和性能优化 转
JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型: 多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...
- JVM内存模型和性能优化
JVM内存模型优点 内置基于内存的并发模型: 多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于数据库锁. 多核并行计算模 ...
- jvm-java内存模型与锁优化
java内存模型与锁优化 参考: https://blog.csdn.net/xiaoxiaoyusheng2012/article/details/53143355 https://blog.csd ...
- 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)
前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...
- 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化
<深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...
- 通过实例程序验证与优化谈谈网上很多对于Java DCL的一些误解以及为何要理解Java内存模型
个人创作公约:本人声明创作的所有文章皆为自己原创,如果有参考任何文章的地方,会标注出来,如果有疏漏,欢迎大家批判.如果大家发现网上有抄袭本文章的,欢迎举报,并且积极向这个 github 仓库 提交 i ...
- JMM(java内存模型)
What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...
- 《深入理解Java内存模型》读书总结
概要 文章是<深入理解Java内容模型>读书笔记,该书总共包括了3部分的知识. 第1部分,基本概念 包括"并发.同步.主内存.本地内存.重排序.内存屏障.happens befo ...
- Java内存模型深度解析:volatile--转
原文地址:http://www.codeceo.com/article/java-memory-4.html Volatile的特性 当我们声明共享变量为volatile后,对这个变量的读/写将会很特 ...
随机推荐
- [HttpPost]和[AcceptVerbs(HttpVerbs.Post)]区别
1.共同点:[HttpPost]和[AcceptVerbs(HttpVerbs.Post)]都是只接受POST请求过来的数据. 2.不同点:在MVC中如果想一个action既可以回应POST请求也可以 ...
- Android之仿微信图片选择器
先上效果图.第一张图显示的是“相机”文件夹中的所有图片:通过点击多张图片可以到第二张图所示的效果(被选择的图片会变暗,同时选择按钮变亮):点击最下面的那一栏可以到第三张图所示的效果(显示手机中所有包含 ...
- 在Swift中实现单例方法
在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...
- socket.io简单入门(一.实现简单的图表推送)
引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...
- 关于手机的内置SD卡与外置SD卡
对于安卓2.3的系统来说,Environment.getExternalStorageDirectory()获取的目录是内置SD卡还是外置SD卡是无法保证的, 和手机厂商的修改有关,只能通过Envir ...
- Doctype的作用
<!DOCTYPE> 声明不是 HTML 标签:它是指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令,也就是定义文档类型. 所有的浏览器都需要两种模式:怪异模式和严格模式 ...
- DOM0编程与基础方法
## 这里记录一下DOM编程的基础与方法----### DOM 的O:对象 objectO表示Object,对象的意思.JavaScript中对象可以分为三种类型1. 用户定义对象(user-defi ...
- Mongo基础使用,以及在Express项目中使用Mongoose
MongoDB的基本使用 MongoDB特点: 使用BSON存储数据 支持相对丰富的查询操作(相对其他nosql数据库) 支持索引 副本集(支持多个实例/多个服务器运行同个数据库) 分片(数据库水平扩 ...
- Bootstrap表单验证插件bootstrapValidator使用方法整理
插件介绍 先上一个图: 下载地址:https://github.com/nghuuphuoc/bootstrapvalidator 使用方法:http://www.cnblogs.com/huangc ...
- Python全栈开发【基础四】
Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...