JVM调优推荐


posts - 233, comments - 205, trackbacks - 0

注意:本系列博客,主要参考自如下四本书html

《分布式Java应用:基础与实践》《深刻理解Java虚拟机(第二版)》《深刻分析Java web技术内幕》《实战java虚拟机》前端

一、为何要了解JVM内存管理机制java

  • JVM自动的管理内存的分配与回收,这会在不知不觉中浪费不少内存,致使JVM花费不少时间去进行垃圾回收(GC)
  • 内存泄露,致使JVM内存最终不够用

二、JVM内存结构linux

根据上图,JVM内存结构包括:git

  • 方法区(也就是"持久代"),java8里完全被移除,取而代之的是元数据区
  • 栈(在hotspot JVM中,JVM方法栈--Java虚拟栈,与本地方法栈是同一个)
  • PC寄存器(程序计数器)

还有一块:web

  • 直接内存:直接向系统内存申请的一块内存区域,javaNIO会使用,速度优于java堆内存。- 隶属于物理内存,不属于JVM内存

注意点:spring

  • 堆是GC的主要区域,方法区、直接内存也会发生GC
  • 栈与PC寄存器是每一个线程都会建立的私有区域,不会GC
  • 直接内存使用速度因为堆内存,可是内存的申请速度低于堆内存

2.一、方法区docker

  • 存放内容(类的信息、类static属性、方法、常量池)
    • 已经加载的类的信息(名称、修饰符等)
    • 类中的static变量
    • 类中的field信息
    • 类中定义为final常量
    • 类中的方法信息
    • 运行时常量池:编译器生成的各类字面量和符号引用(编译期)存储在class文件的常量池中,这部份内容会在类加载以后进入运行时常量池,class文件的常量池查看 第三章 类文件结构与javap的使用
  • 使用实例:反射,在程序中经过Class对象调用getName等方法获取信息数据时,这些信息数据来源于方法区。
  • 调节参数
    • -XX:PermSize:指定方法区的最小值,默认为16M
    • -XX:MaxPermSize:指定方法区的最大值,默认为64M
  • 所抛错误
    • 方法区域要使用的内存超过了其容许的大小时,抛出OutOfMemoryError
  • 内存回收的主要目标
    • 对类的卸载(这也是为何不少企业使用velocity等模板引擎作前端而不是使用jsp的缘由之一)
    • 针对常量池的回收
  • 总结
    • 通常而言,在企业开发中,-XX:PermSize==-XX:MaxPermSize
    • 一般,这个大小设置为256M就没问题了,固然还要根据本身的程序去预估,并在运行过程当中去调整,这里以在Resin服务器中配置为例
      View Code
    • 类中的static变量会在方法区分配内存,可是类中的实例变量不会(类中的实例变量会随着对象实例的建立一块儿分配在堆中,固然如果基本数据类型的话,会随着对象的建立直接压入操做数栈)
    • 关于方法区的存放内容,能够这样去想全部的经过Class对象能够反射获取的都是从方法区获取的(包括Class对象也是方法区的,Class是该类下全部其余信息的访问入口)

注意:常量池在jdk1.6在方法区;在jdk1.7在堆json

附:元数据区数组

  • 调节参数:-XX:MaxMetaspaceSize,若是不指定大小,极限状况下可能耗尽系统全部内存
  • 元数据区是堆外的一块直接内存

2.二、堆

  • 存放内容
    • 对象实例(类中的实例变量会随着对象实例的建立一块儿分配在堆中,固然如果基本数据类型的话,会随着对象的建立直接压入操做数栈),这一点查看 第四章 类加载机制
    • 数组值
  • 使用实例
    • 全部经过new建立的对象都在这块儿内存分配,具体分配到年轻代仍是年老代须要根据配置参数而定(新建对象直接分配到年老代有两种状况,看下边)
  • 调节参数
    • -Xmx:最大堆内存,默认为物理内存的1/4但小于1G
    • -Xms:最小堆内存,默认为物理内存的1/64但小于1G
    • -XX:MinHeapFreeRatio,默认当空余堆内存小于最小堆内存的40%时,堆内存增大到-Xmx
    • -XX:MaxHeapFreeRatio,当空余堆内存大于最大堆内存的70%时,堆内存减少到-Xms
  • 注意点
    • 在实际使用中,-Xmx与-Xms配置成相等的,这样,堆内存就不会频繁的进行调整了
  • 抛出错误
    • OutOfMemoryError:在堆中没有内存完成实例分配(关于实例内存的分配,以后再说),此时堆内存已达到最大没法扩展时。
  • 堆内存划分

    • 新生代
      • 组成:Eden+From(S0)+To(S1)
      • -Xmn:整个新生代的大小
      • -XX:SurvivorRatio:调整Eden:From(To)的比率,默认为8:1
    • 年老代
      • 新建对象直接分配到年老代,两种状况
        • 大对象:-XX:PretenureSizeThreshold(单位:字节)参数来指定大对象的标准,在Parallel Scavenge GC下可能无效,具体见《第五章 JVM垃圾收集器(1)
        • 大数组:数组中的元素没有引用任何外部的对象
  • 总结
    • 企业开发中,-Xmx==-Xms
    • 一般,-Xmx设置为2048m就没问题了,固然还要根据本身的程序去预估,并在运行过程当中去调整,这里以在Resin服务器中配置为例
      View Code

      能够看到,-Xms==-Xmx==2048m,年轻代大小-Xmn==512m,这样,年老代大小就是2048-512==1536m,这个比率值得记住,在企业开发中,年轻代:年老代==1:3,而此时,咱们配置的-XX:MaxTenuringThreshold=15(这也是默认值),年轻代对象通过15次的复制后进入到年老代(关于这一点,在以后的GC机制中会说),

    • -XX:MaxTenuringThreshold与-XX:PretenureSizeThreshold不同,不要看错

2.三、栈

  • 注意点
    • 每条线程都会分配一个栈,每一个栈中有多个栈帧(每个方法对应一个栈帧)
    • 线程建立的时候建立一个线程的java栈
    • 每一个方法在执行的同时都会建立一个栈帧,每一个栈帧用于存储当前方法的局部变量表、操做数栈等,具体查看本文第一个图,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程,说的更明白一点,就是方法执行时建立栈帧,方法结束时释放栈帧所占内存
  • 存放内容
    • 局部变量表:八大基本数据类型数据、对象引用。该空间在编译期已经分配好,运行期不变。
    • 操做数栈:是执行引擎直接操做的部分
  • 调节参数
    • -Xss:设置栈的大小,一般设置为1m就好
      View Code
  • 支持native方法执行(本地方法栈)
  • 所抛错误
    • StackOverFlowError:线程请求的栈深度大于虚拟机所容许的深度。
      • 栈的深度就是方法调用嵌套的层数,受限于-Xss的大小
      • 典型场景:没有终止条件的递归(递归基于栈)。
      • 每一个方法的栈的深度在javac编译以后就已经肯定了,查看 第三章 类文件结构与javap的使用
    • OutOfMemoryError:虚拟机栈能够动态扩展,若是扩展的时候没法申请到足够的内存。
      • 须要注意的是,栈能够动态扩展,可是栈中的局部变量表不能够。

2.四、PC寄存器(程序计数器)

  • 概念:当前线程所执行的字节码的行号指示器,用于字节码解释器对字节码指令的执行。
  • 多线程:经过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个时刻,一个处理器(也就是一个核)只能执行一条线程中的指令,为了线程切换后能恢复到正确的执行位置,每条线程都要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。

附:对象分配(《实战java虚拟机》)

posted on 2016-02-03 15:40 赵计刚 阅读(2025) 评论(1) 编辑 收藏

FeedBack:
2018-03-09 19:06 | Tobin
赞,mark
昵称: 赵计刚
园龄: 3年
粉丝: 572
关注: 22

< 2019年1月 >
30 31 1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31 1 2
3 4 5 6 7 8 9
Copyright ©2019 赵计刚 Powered By 博客园 模板提供: 沪江博客
相关文章
相关标签/搜索