zoukankan      html  css  js  c++  java
  • java基础---JVM---调优,垃圾收集器,内存分配策略

    ===曾经出现哪些虚拟机内存溢出的问题呢?如何解决的呢?
    pregen space out of memory的问题,内存溢出问题。
    tomcat这样设置:
    TOMCAT_HOMEincatalina.bat 中添加这样一句话:
    set JAVA_OPTS= -Xmx1024M -Xms512M -XX:MaxPermSize=256m
     
     
    ===?Java虚拟机使用什么算法判断对象死了呢?
    两种算法
    1.引用计数算法,为每个对象创建一个引用计数器,有地方引用就加1,引用失效了就减一。
    引用计数法很难解决循环引用的问题:
    2.根搜索算法
    从根GC roots根对象开始寻找路径到目的对象,如果这个对象不可达,即使说它有其他的引用,仍然是可以回收的。
    ===?哪些对象可以作为GC ROOTS呢?
    栈:虚拟机栈里面的引用所指向的对象
         本地方法栈里面引用所指向的对象
    方法区:静态变量引用的对象
                常量引用的对象。
     
     
    3.2对象已死吗?
    ===?虚拟机执行回收的具体过程是什么样的?进入销毁队列的对象还有可能存活吗?
    1.先判断每个对象是否要执行finalize()方法。如果对象没有覆盖finalize()方法,因为finalize是object带的方法原先为空 ,或者虚拟机已经执行过一次finalize()方法了,那么该对象是“没必要执行finalize()方法的”。
    2.否则有必要执行finalize。
    1)将对象放入F-Queue队列中,排队执行finalize()方法
    2)如果这个时候有引用指向这个对象,就从队列中逃脱
    3)否则执行finalize()进行回收。
     

     
    3.3垃圾收集算法
    ===?有几种垃圾收集算法呢?分别有什么优缺点?
     
    标记清除法:统一标记要回收的对象再统一清除。缺点1,标记清除本身消耗性能 2.产生内存碎片,不利于后续申请大面积的连续的内存空间
     
    复制法:内存分两块,用完一块就复制到另一边,原先那块就空出来了。缺点:如果对象存活的比较多,那么复制的就会比较多,消耗性能。2.内存变成一半了。商业虚拟机的新生代使用的方法。新生代存活的比较小,复制算法块。hotspot新生代使用这种方法,默认的eden区域和survivor区域比例是8:1
     
    标记压缩法:将存活的对象压缩移动到一边,清理掉边界以外的内存。老年代使用的方法。为什么老年代使用这个方法呢,因为老年代的对象存活很久都很稳定了,那么需要进行GC处理的对象比较少了,用复制算法不划算。
     
    分代收集算法:将堆内存分成新生代和老年代。新生代容易死,所以使用复制法,老年代存活的多,所以使用标记清除算法或者标记整理算法。
     
    ===?为什么商业虚拟机喜欢使用复制法来处理新生代呢?
    因为新生代容易死亡,也就是说最后复制的对象比较少,存活下来的比较少。所以分配的内存不需要进行1:1的分配。
     
    ===?什么是Minor GC和FULL GC呢?
    Minor GC:新生代的GC,java对象存活时间很短,频繁死亡,所以Minor GC很频繁,回收速度较快。
    FULL GC:老年代的GC,速度慢
     
    ===?为什么需要堆内存分区,分为哪些区域呢?
    因为不同的对象生命周期不同,要使用不同的内存分配策略和垃圾回收策略提高jvm的效率,所以分区。
    分为新生代区,老年区,永久存储区。
     

     
    ===?内存分配的策略有五个?
    1.新创建的对象优先进入eden区
    内存分为新生代区和老年区
    1)eden区是新生代的区,和survivor区比例是8比1。
    2)当eden区容纳不了新的对象的时候触发minor gc新生代垃圾回收,并将eden区存活的对象放入survivor。
    3)survivor比较小放不下的时候,就将对象转存到老年区去。
     
    2.大对象直接进入老年区。什么是大对象?为什么?如何进行设置
    1)大对象指的是需要大量连续内存空间的对象,比如大数组大字符串
    2)因为内存空间碎片很多的时候出现大对象就会触发垃圾回收,因为没有空间给它存这么一大个连续的对象。如果一直有大对象进来就会一直垃圾回收,会很消耗性能。
    3)通过设置参数-XX:PretenureSizeThreshold来控制多大的对象直接存入到老年区
     
    3.长期存活的对象进入老年区
    如何判断一个对象的年龄呢?-XX:MaxTenuringThreshold=7
    1)对象躲过第一次Minor GC新生代垃圾回收之后可能会移动到Survivor区域,这个时候1岁
    2)在Survivor经历多次Minor GC之后,岁数一直增大,超过某个阈值的时候就会被转存到老年区了。
     
    4.动态对象年龄判定
    survivor区的对象不一定要到一定年限才转存到老年区。
    因为内存可能不够,所以当》=某个年龄段的所有对象内存超过一半就直接转存到老年区。
     
    5.空间分配担保
    1)当老年区可用内存空间大于新生代对象总和的时候能够保证这次GC(垃圾回收)是安全的
    2)老年区可用区域小于新生代内存总和:会算历次转移到老年区的对象平均值,平均值小于可用内存的话会进行冒险。平均值大于可用的话就直接进行FULL GC就是老年区的垃圾回收。
    目的:尽量减少老年区的内存回收
     

    JVM有哪几种垃圾收集器呢?
    1. 串行垃圾回收器(Serial Garbage Collector)
    2. 并行垃圾回收器(Parallel Garbage Collector)
    3. 并发标记扫描垃圾回收器(CMS Garbage Collector)
    4. G1垃圾回收器(G1 Garbage Collector)
    串行垃圾回收器:一个线程进行垃圾回收,回收的时候其他线程中断运行
     
    并行垃圾回收器:多个线程同时进行,回收的时候其他线程中断运行。
     
    CMS并发标记扫描垃圾回收器:见专题
     
    G1垃圾回收器:见专题

     
    虚拟机的内存调优和垃圾回收器的选择。
    ===为什么要进行虚拟机的垃圾回收GC优化呢?垃圾回收面临的最大问题是什么呢?如何达到实时性呢?传统的堆空间使用方式的弊端?新的算法的优势?G1垃圾回收器的优势?
    因为java虚拟机在垃圾回收的时候会停止应用程序的执行,其他线程会进行等待,等待回收线程执行完。所以GC优化的目的就是减少垃圾回收的次数。
    垃圾回收的最大问题就是GC停顿问题,应用停顿,请求就会堆积起来甚至请求失败,传统的方式就是让堆变小,这样垃圾回收的时间就会很短,但是吞吐量就无法保证了。
    传统的使用方式将整个堆作为一个内存块使用,等到空间不足了才做GC,会产生碎片,要压缩就会要暂停。
    为了达到实时性,那么需要短的暂停时间,同时需要很大的内存空间支持。这个时候使用增量收集的方式。内存分为多块,每次使用其中一部分,垃圾收集的时候把存活的放到没用的那部分空间中。
     
    ===常见的虚拟机参数设置
    java -Xmx1024m -Xms1024m -Xmn512m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=64m -XX:MaxTenuringThreshold=0
     
    堆空间的参数设置
    -Xms3550m:初始化堆空间大小
    -Xmx3550m:最大堆空间大小
    -Xss1m:线程栈空间大小
    -Xmn2g:新生代大小
    堆内空间分配
    -XX:NewSize=1024m:新生代空间
    -XX:MaxNewSize=1024m:最大新生代空间大小
    -XX:PermSize=256m:永久代大小
    -XX:MaxPermSize=256m:最大永久代大小
    -XX:NewRadio=4:老年代占4份
    -XX:SurvivorRadio=4:新生代占4份
    -XX:MaxTenuringThreshold=7:在survivor停留几次垃圾回收会进入老年代
     
    垃圾回收器参数设置
    ------串行和并行垃圾收集器(垃圾回收的时候应用会暂停)
    -XX:+UseSerialGC:串行垃圾回收器
    -XX:+UseParallelGC:并行垃圾回收器只对新生代有效
    -XX:ParallelGCThreads=20:并行垃圾回收线程数量
    -XX:+UseParallelOldGC:老年代使用并行回收
    GC时间控制
    -XX:GCTimeRadio=99:用于垃圾回收的时间占百分之一,保证吞吐量
    -XX:MaxGCPauseMilis=100:最大新生代GC停留时间毫秒。无法满足的话就会自动调整新生代大小
    -XX:+UseAdaptiveSizePolicy:会自动调整新生代中eden和survivor比例来达到最低响应时间和收集频率。
     
    -----并发收集器(垃圾回收的时候不暂停,响应时间快,因为使用标记清除法所以存在内存碎片问题)
    -XX:+UseConcMarkSweepGC:
    CMS并发垃圾回收器,年老代为并发收集。可以设置几次GC后压缩,开启压缩。
    适用于响应时间需求大的情况,目的是减少FULL GC发生的几率。
    在老年代垃圾回收的时候,会停两次,多线程进行并行收集。因为应用不停,所以会有浮动垃圾产生,一般需要使用百分二十预留空间处理浮动垃圾,因为应用不停要保证在垃圾回收的过程中有充足的内存空间使用,否则出现异常concurrent mode failure
    -XX:CMSInitiatingOccupancyFraction=256m:指定堆剩余多少的时候进行并发收集。
    -XX:+UseParNewGC:和CMS配合使用,设置新生代为并行收集。与-XX:ParallelGC的区别在于后者不能够和CMS一起使用。
    -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
    打开对年老代的压缩,年老代经过5次GC的时候进行压缩整理。
     
    关于辅助信息,打印信息供调试使用。
    -XX:+PrintGC   输出gc信息
    -XX:+PrintGCDetails    输出gc详细信息
    -XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与
    上面两个混合使用
    -XX:+PrintGCApplicationConcurrentTime: 打印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
    -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间。可与上面混合使用
    -XX:PrintHeapAtGC: 打印GC前后的详细堆栈信息
     
     
    ===如何选择垃圾收集器
    吞吐量优先:有个很大的年轻代和较小的老年代,对响应时间没有要求可以使用并行。
    响应时间优先:年轻代尽量大,使用CMS收集老年代
    • 串行处理器: 
      --适用情况:数据量比较小(100M左右);单处理器下并且对响应时间无要求的应用。
      --缺点:只能用于小型应用
    • 并行处理器:
      --适用情况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。
      --缺点:应用响应时间可能较长
    • 并发处理器:
      --适用情况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。
     
     
    ===垃圾回收器的选择
     
     
     
     
     
     
  • 相关阅读:
    Java 调用存储过程、函数
    Java BaseDao
    写好Java代码的30条经验总结
    15款Java程序员必备的开发工具
    Oracle基础 表分区
    Oracle基础 索引
    Oracle基础 触发器
    Oracle基础 程序包
    Oracle基础 自定义函数
    Oracle基础 存储过程和事务
  • 原文地址:https://www.cnblogs.com/buptyuhanwen/p/9413950.html
Copyright © 2011-2022 走看看