JVM内存区域

(1)程序计数器
看做当前线程所执行的字节码行号显示器;任意时刻,一个CPU都会执行一条线程中的指令,为了线程切换后能回到正确位置,每个线程都需要一个独立的线程计数器;执行native方法时,计数器值为空;此区域没有任何OutOfMemoryError的区域;

(2)虚拟机栈
虚拟机栈的生命周期和线程同步,虚拟机栈中的局部变量表用于存储各种基本数据类型、对象引用类型;long和double会占用两个局部变量表的空间,局部变量表在编译器完成空间分配;
StackOverflowError:线程请求过多
OutOfMemoryError:如果虚拟机栈扩展时无法申请到足够内存;

(3)本地方法栈
与虚拟机栈发挥的作用非常相似,区别是:虚拟机栈为Java方法服务的;本地方法栈是为native方法服务的;

(4)Java堆
存放实例对象的以及数组的;
OutOfMemoryError异常;

堆内存划分:

Young Generation:新生代
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区:一个Eden ['i:dən]区,两个 Survivor[sə'vaɪvə]区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor[sə'vaɪvə]区(两个中的一个),当这个 Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区。

Old Generation:老年代
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

Perm Area:永久带
用于存放静态文件,如今Java类、方法等。

(5)方法区
虚拟机加载的类信息,常量,静态变量等;
运行时常量池也是方法区的一部分:存放编译器生成的各种字面量和符号引用;
OutOfMemoryError异常;

Java对象创建以及内存布局

(1)虚拟机执行new指令 ----> 检查指令参数是否能在常量池中定位到类的符号引用 ----> 如果没有检查到引用代表的类,则先执行类的加载过程 ----> 类加载通过后,为新生对象分配内存 ----> 分配到的内存空间初始化为零 ----> 虚拟机对对象进行设置 ----> 执行init方法,完成对象创建
(2)对象在内存中存储布局可分为3块区域:
对象头:一部分存储对象自身运行时数据,如hashCode,线程持有的锁等;一部分是类型指针,确定对象是哪个类的实例;
实例数据:就是程序代码中定义的各种类型字段内容;
对齐填充:没有特殊含义,仅仅起到占位符的作用;

垃圾回收器和内存分配策略

如何判断对象已经死亡,既内存需要回收?

  • 引用计数器法:给对象添加一个引用计数器,每当一个地方引用它时,计数器值加一;引用失效,计数器值一,值为零时对象就不再使用了;缺点时无法解决对象之间的循环引用;
  • 可达性分析算法:当一个对象到 GC root 没有任何引用链时证明对象不可用了;


Java语言中可作为GC roots的对象有:
虚拟机栈引用的对象,方法区中类的静态属性、常量引用的对象,本地方法区中Native方法引用的对象;

垃圾收集算法

(1)标记-清除算法:
首先标记处所有需要回收的对象,标记完成后统一回收;执行下图所示:

主要有两个缺点:一是执行效率不高,另一个是会产生大量不连续的内存碎片,导致再次分配较大对象时,无法得到连续的内存空间而再一次触发垃圾回收机制;

(2)复制算法:
为了解决标记-清除算法的效率问题,可以使用复制算法;它将内存划分为大小相等的两块,每次使用其中一块,当一块内存使用完了,就将存活的对象复制到另一块,然后回收已使用过的内存;

该算法在对象存活较多时,效率底下,同时内存空间浪费;适合于新生代内存;

(3)标记-整理算法:
标记所有可回收对象,它不是直接对可回收对象进行清理;而是让所有的存活对象都向一端移动,然后直接清理掉端边界以外的内存;

(4)分代收集算法:
目前商业虚拟机都采用分代收集算法。

Java中垃圾回收器类型

垃圾回收器种类

  • Serial ['sɪərɪəl]收集器
    新生代收集器,使用复制算法,使用一个线程进行GC,串行,其它用户工作线程暂停。该收集器简单高效。
  • ParNew [pɑː][njuː]收集器
    新生代收集器,使用复制算法,Serial收集器的多线程版,用多个线程进行GC,并行,其它工作线程暂停。使用-XX:+UseParNewGC开关来控制使用ParNew+Serial Old收集器组合收集内存;使用-XX:ParallelGCThreads来设置执行内存回收的线程数。
  • Parallel Scavenge 收集器
    吞吐量优先的垃圾回收器,作用在新生代,使用复制算法,关注CPU吞吐量,即运行用户代码的时间/总时间。使用-XX:+UseParallelGC开关控制使用Parallel Scavenge+Serial Old收集器组合回收垃圾。
  • Serial Old收集器
    老年代收集器,单线程收集器,串行,使用标记整理算法,使用单线程进行GC,其它工作线程暂停。
  • Parallel Old ['pærəlel]收集器
    吞吐量优先的垃圾回收器,作用在老年代,多线程,并行,多线程机制与Parallel Scavenge差不错,使用标记整理算法,在Parallel Old执行时,仍然需要暂停其它线程。
  • CMS(Concurrent Mark Sweep)收集器
    老年代收集器,致力于获取最短回收停顿时间(即缩短垃圾回收的时间),使用标记清除算法,多线程,优点是并发收集(用户线程可以和GC线程同时工作),停顿小。使用-XX:+UseConcMarkSweepGC进行ParNew+CMS+Serial Old进行内存回收,优先使用ParNew+CMS(原因见Full GC和并发垃圾回收一节),当用户线程内存不足时,采用备用方案Serial Old收集。

如何读懂 GC 日志

其实每个垃圾回收器的日志是不一样的,但是为了方便查看日志它们也有一定的共性,如下所示的一段 GC 日志:

33.125: [GC [DefNew: 3324k->152k(3712k),0.0025925 secs] 3324->152k(11904k),0.003168 secs]100.667: [Full GG [Tenurend: 0k->210k(1024k),0.00149142 secs]4603k->210k(19456k),
[Perm : 2999k->2999k(21248k)],0.0150007 secs] [Times:user=0.01 sys=0.00,real=0.02 secs]
  • 日志最前面的数字 "33.125:"和"100.667:" 表示GC发生的时间,是从Java虚拟机启动以来经过的时间
  • "[DefNew"、"[Tenured"、"[Perm"表示GC发生的时间,这里显示的区域名称和使用GC收集器密切相关,上面例子中使用的Serial收集器,它的新生代命名为Default New Generation,所以显示"[DefNew"
  • 方括号内部的3324k->152k(3712k)表示"GC前该区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)"
  • 方括号外的3324->152k(11904k)表示"GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆总容量)"
  • "0.0025925 secs"表示该内存区域GC所用时间,单位秒

和GC有关的JVM参数

做GC调优需要大量的实践,耐心和对项目的分析。做GC的调优很大程度上依赖于对系统的分析,系统拥有怎样的对象以及他们的平均生命周期。举个例子,如果一个应用大多是短生命周期的对象,那么应该确保Eden区足够大,这样可以减少Minor GC的次数。可以通过-XX:NewRatio来控制新生代和老年代的比例,比如-XX:NewRatio=3代表新生代和老年代的比例为1:3。需要注意的是,扩大新生代的大小会减少老年代的大小,这会导致Major GC执行的更频繁,而Major GC可能会造成用户线程的停顿从而降低系统吞吐量。JVM中可以用NewSize和MaxNewSize参数来指定新生代内存最小和最大值,如果两个参数值一样,那么就相当于固定了新生代的大小。

(1)Minor ['maɪnə] GC:从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC;
(2)Major['meɪdʒə] GC:是清理老年代;
(3)Full GC:是清理堆空间,包括年轻代和老年代;
参考文章:Minor GC,Major GC,Full Gc

GC参数了解

内存相关常用参数

(1) -Xms : 堆内存的初始大小,默认是物理内存的1/64
(2) -Xmx : 堆内存的最大值,默认不超过物理内存
(3) -Xmn : 年轻代堆内存大小
(4) -Xss : 栈内存大小设置
(5) -XX:PermSize : 内存永久区的初始大小
(6) -XX:MaxPermSize : 内存永久区的大小
(7) -XX:SurvivorRatio : Eden区与Survivor区的大小比值;设置成8,则两个Survivor区与一个Eden区的比值是2:8
(8) -XX:+UseAdaptiveSizePolicy : 动态调整 Java 堆内存中各个区域的大小以及即进入老年代的年龄

收集器使用相关参数

(1) -XX:UseParallelGC : 使用 Parallel Scavenge(年轻代并行的多线程收集器) + Serial Old(老年代单线程收集器) 收集器
(2) -XX:UseParNewGC : 使用 ParNew + Serial Old 收集器
(3) -XX:ParallelGCThreads : 并行收集的线程数
(4) -XX:UseParallelOldGC : 使用 Parallel Scavenge(年轻代并行的多线程收集器) + Parallel Old 收集器
(5) -XX:MaxGCPauseMillis : 设置GC的最大停顿时间,仅在使用 Parallel Scavenge 收集器时生效
(6) -XX:+UseConcMarkSweepGC : 使用 ParNew + CMS + Serial Old 组合收集器
(7) -XX:GCTimeRatio : GC时间占总时间的比例,默认99,即允许 1% 的GC时间。仅在使用 Parallel Scavenge 收集器时生效

调试参数:

(1) -XX:+DisableExplicitGC : 忽略来自程序中System.gc()方法触发的垃圾回收
(2) -XX:+PrintGCDetails : 打印GC的相信信息
(3) -XX:+PrintHeapAtGC :
(4) -XX:+PrintTenuringDistribution :
(5) -XX:+PrintGCTimeStamps : 打印GC停顿耗时
(6) -XX:+PrintGCDateStamps :
(7) -XX:+HeapDumpOnOutOfMemoryError :
(8) -XX:ErrorFile :
(9) -XX:HeapDumpPath :

-XX:CMSFullGCsBeforeCompaction=0 : cms 收集器每次进入Full GC都进行碎片整理
-XX:+UseCMSCompactAtFullCollection
-XX:CMSInitiatingOccupancyFraction=80 : cms 收集器触发比例(当空间使用了80%后就触发回收)
-XX:ReservedCodeCacheSize=128m :
-XX:InitialCodeCacheSize=128m

jd线上机器jvm参数设置:

/export/servers/jdk1.6.0_25/bin/java -server

-Xms128M -Xmx256M -Xss256K
-XX:PermSize=32M
-XX:MaxPermSize=32M
-XX:+UseAdaptiveSizePolicy
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:GCTimeRatio=39
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps -Xloggc:/export/home/tomcat/logs/loghub.360buy.com/jcollector/gc.log
-XX:+HeapDumpOnOutOfMemoryError
-XX:ErrorFile=/export/home/tomcat/logs/loghub.360buy.com/jcollector/hs_err.log
-XX:HeapDumpPath=/export/home/tomcat/logs/loghub.360buy.com/jcollector/heap_dump.hprof -classpath

mt线上机器jvm参数设置:

JVM_ARGS="-server -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.io.tmpdir=/tmp -Djava.net.preferIPv6Addresses=false"
JVM_GC="

-XX:+DisableExplicitGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintTenuringDistribution
-XX:+UseConcMarkSweepGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps

"
JVM_GC=$JVM_GC"

        -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80"

JVM_HEAP="

    -XX:SurvivorRatio=8 -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -XX:ReservedCodeCacheSize=128m -XX:InitialCodeCacheSize=128m
"

JVM_SIZE="-Xmx4g -Xms4g -Xmn1g"

参考文章
JDK 1.8内存模型
全面理解Java内存模型
年轻代、年老点和持久代

【JVM】第1篇:JVM内存模型相关推荐

  1. JVM初学之堆的内存模型

    定义: 堆是JVM运行时内存区域中最大的一个区域,我们平常创建的对象,数组的内存都是在堆上分配的. 堆不仅仅只是一块大区域,它分为多个不同作用的区域. Old区. Young区.Young区又分为Ed ...

  2. JVM:高效并发机制——内存模型、线程、锁

    为什么要进行并发(多任务处理) 处理器能力很强,尽可能压榨其劳动力 处理器处理速度与存储和通信速度相差甚大(IO.网络通信.数据库访问非常耗时),使得处理器总处在等待的状态,浪费计算资源 物理机提高处 ...

  3. 【JVM学习04】JMM内存模型

    文章目录 1. 原子性 1.1 原子性 1.2 问题分析 1.3 解决方法 2. 可见性 2.1 退不出的循环 2.2 解决方法 2.3 可见性 3. 有序性 3.1 诡异的结果 3.2 解决方法 3 ...

  4. jvm系列二:Java8内存模型-永久代(PermGen)和元空间(Metaspace)

    原文地址:https://www.cnblogs.com/paddix/p/5309550.html 一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地 ...

  5. Java并发篇_Java内存模型

    在并发编程中,我们通常会遇到以下三个问题:原子性问题,可见性问题,有序性问题.那么它们产生的原因和在Java中解决的办法又是什么呢? 一.内存模型的相关概念 ​ 计算机在执行程序时,每条指令都是在CP ...

  6. JVM笔记1:Java内存模型及内存溢出

    灰色:所有线程间共享 白色:线程间隔离 程序计数器:当前线程所执行的字节码的行号指示器,字节码解释器通过改变该计数器的值来选取下一条需要执行的字节码指令. 1,一块很小的内存空间 2,每条线程都需要一 ...

  7. JVM第三篇 — JVM是怎么工作的?

    2019独角兽企业重金招聘Python工程师标准>>> 本文摘自: http://blog.163.com/guixl_001/blog/static/417641042010829 ...

  8. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  9. jvm(12)-java内存模型与线程

    [0]README 0.1)本文部分文字描述转自"深入理解jvm",旨在学习"java内存模型与线程" 的基础知识: [1]概述 1)并发处理的广泛应用是使得 ...

  10. JVM内存模型与GC回收器

    1.JVM内存模型 JVM内存模型如上图,需要声明一点,这是<Java虚拟机规范(Java SE 7版)>规定的内容,实际区域由各JVM自己实现,所以可能略有不同.以下对各区域进行简短说明 ...

最新文章

  1. fun函数是什么php,c语言fun函数有什么例题?
  2. Excel 向程序发送命令时出现问题 解决方法 VS
  3. LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
  4. 安卓应用安全指南 4.2.2 创建/使用广播接收器 规则书
  5. 前端ajax数据提交到服务器_详解前端如何让服务器主动向浏览器推送数据
  6. 项目管理综述(需要完善)
  7. 通俗易懂理解Attention机制
  8. 使用XUtils进行文件的断点下载
  9. 拓端tecdat|R语言画ROC曲线总结
  10. Ubuntu 重置密码
  11. 企业如何避交所得税__公司如何才能少交企业所得税
  12. Oracle 实验:建立和配置Oracle数据库服务器
  13. 2021年4月2日 星期五 农历二月 阴
  14. 【Cadence使用】PCB元器件匹配3D模型
  15. 与麻花兄弟诉苦兼讨论欠缺的知识
  16. veracrypt 创建文件型加密卷
  17. SPSS Modeler 建模前准备—数据平衡与特征选择(指南 第十一章)
  18. 如何解决MySql报错:only_full_groupBy
  19. 尚学堂Java面试题整理
  20. 使用JS实现博客搜索关键字高亮

热门文章

  1. 字节跳动高工面试:mysql查询重复数据sql
  2. java随机生成数字代码,详解系列文章
  3. Struts结合梅花雪实现动态生成树
  4. activity销毁时执行执行方法是_[Android开发 VIII ]销毁一个activity
  5. linux系统ssh服务无法启动,Linux上的SSH无法启动
  6. Vue使用nextTick的原因和作用
  7. 8个JavaScript题目
  8. 关于JS括号匹配的面试题
  9. 最新html取消dynsrc属性无效,HTML属性标签2
  10. 乔治亚理工学院计算机专业,乔治亚理工学院