8.JVM

jvm
    所谓虚拟机就是一台虚拟的机器,他是一款软件,用来执行一系列虚拟计算机指令,大致分为
        系统虚拟机和程序虚拟机。Visual Box、VMare就是系统虚拟机,程序虚拟机代表就是jvm
        虚拟机 。
        
            类加载子系统、方法区、java堆、直接内存、java栈、本地方法、垃圾回收系统、pc寄存器、执行引擎
    
        类加载子系统:负责从文件系统或则网络中加载Class信息,加载的信息存放在一块称之为
            方法区的内存空间
            
        方法区:就是存放类信息、常量信息、常量池信息、包括字符串字面量和数字常量等
        
        java堆:在java虚拟机启动的时候建立java堆,他是java程序最主要的内存工作区域,几乎所有
            的对象实例都存放到java堆中,堆空间是所有线程共享的
            
        直接内存:java的NIO库允许java程序使用直接内存,从而提高性能,通常直接内存速度会优于    
            java堆。读写频繁的场合可能会考虑使用
            
        Java栈:每个虚拟机线程都有一个私有的栈,一个线程的java栈在线程创建的时候被创建,Java栈
            中保存着局部变量、方法参数、同时java的方法调用、返回值等
            
        本地方法栈:和java栈非常类似,最大不同为本地方法栈用于本地方法调用。java虚拟机允许java
            直接调用本地方法(通常使用C编写)
            
        垃圾收集系统:是java核心,也是必不可少的,java有一套自己进行垃圾清理的机制,开发人员无需
            手工清理。
        
        pc寄存器:是每个线程私有的空间,java虚拟机会为每个线程创建PC寄存器,在任意时刻,一个java
            线程总是在执行一个方法,这个方法被称为当前方法,如果方法不是本地方法,PC寄存器就会执行
            当前正在被执行的指令,如果是本地方法,则PC寄存器值为undefined,寄存器存放如当前执行环境
            指针、程序计数器、操作栈指针、计算的变量指针等信息。
            
        执行引擎:最核心的组件就是执行引擎了,他负责执行虚拟机的字节码,一般会先进行编译成机器码后执行

    堆解决是数据存储的问题,栈解决程序的运行问题,方法区是辅助堆栈的快永久区
    
    辨析java堆
    
        java堆是和java应用程序关系最密切的内存空间,几乎所有的对象都存放在其中,并且java堆完全是自动
            化管理的,通过垃圾回收机制,垃圾对象会自动清理,不需要显示地释放。
            
        根据垃圾回收机制不同,java堆有可能拥有不同的结构,最常见的就是将整个java堆分为新生代和老年代。
            其中新生代存放新生的对象或者年龄不大的对象,老年代tenured则存放老年对象。
        
        新生代分为eden区、s0区、s1区,其中s0和s1也被称为from和to区域,他们是两块大小相等并且可以互换角色的空间
        
        绝大多数情况下,对象首先分配在eden区,在一次新生代回收后,如果对象还存货,则会进入s0和s1区,
            之后每次经过一次新生代回收,如果对象存活则他的年龄就加1,当对象达到一定年龄后,则进入老年代。
    
    java栈
        java栈是一块私有的内存空间,一个栈,一般有三部分组成:局部变量表、操作数栈而后帧数据区
        局部变量表:用于报错函数的参数及局部变量
        操作数栈:主要保存计算过程的中间结果,同时作为计算过程中变量临时存储空间
        帧数据区:除了局部变量表和操作数栈以外,栈还需要一些数据来支持常量池的解析,这里帧数据区
            保存着访问常量池的指针,方便程序访问常量池,另外,当函数返回或者出现异常时,虚拟机
            必须有一个异常处理表,方便发送异常的时候找到异常的代码,因此异常处理表也是帧数据区的
            一部分。
            
    java方法区:和堆一样,方法区室友一块所有线程共享的内存区域,他保存系统的类信息,比如类的字段、
        方法、常量池等。方法区的大小决定了系统可以保存多少个类,如果系统定义太多的类,导致方法区
        溢出。虚拟机同样会抛出内存溢出错误。方法区可以理解为永久区Perm
    
    虚拟机参数
        虚拟机提供了一些跟踪系统状态的参数,使用给定的参数执行java虚拟机,就可以在系统运行时打印
            相关日志,用于分析实际问题。主要围绕着堆、栈、方法区进行配置
            
        堆分配参数
            -XX:+PrintGC 使用这个参数,虚拟机启动后,只要遇到GC就会打印日志
            -XX:+UseSerialGC 配置串行回收器
            -XX:+PrintGCDetails 可以查看详细详细,包括各个区的情况
            -Xms:设置java程序启动时初始堆大小
            -Xmx:设置java程序能获得的最大堆大小
            -Xmx20m -Xms5m -XX:+PrintCommandLineFlags:可以将隐式或者显式传给虚拟机的参数输出
            //-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags

            总结:-Xms 和 -Xmx 一般设置一样大,为了减少GC次数
        
        新生代的配置
            -Xmn:可以设置新生代的大小,设置一个比较大的新生代会减少老年代的大小,这个参数对
                系统性能以及GC行为有很大的影响,新生代大小一般会设置整个堆空间的三分之一到
                四份之一左右
                
            -XX:SurvivorRatio:用来设置新生代中eden空间和from、to空间的比例。
                含义:-XX:SurvivorRatio=eden/from=eden/to
            //第一次配置
            //-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
            
            //第二次配置
            //-Xms20m -Xmx20m -Xmn7m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
            
            //第三次配置
            //-XX:NewRatio=老年代/新生代
            //-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC

            
            总结:不同的堆分布情况,对系统执行会产生一定的影响,实际工作中,应该根据系统的特点
                做出合理的配置,尽可能将对象预留在新生代,减少老年代的GC次数。
                处理可以设置新生代的绝对大小(-Xmn),还可以使用(-XX:NewRatio)设置新生代和老年代
                的比例:-XX:NewRatio=老年代/新生代
            
        堆内存溢出处理
            java虚拟机提供了-XX:+HeapDumpOnOutOfMemoryError,使用该参数可以在内存溢出是到处整个
                堆信息,与之配合使用的还有-XX:HeapDumpPath,可以设置到处堆的存放路径
            
            //-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/Test03.dump
            
            内存分析工具:Memory Analyzer 1.5.0
            地址:http://download.eclipse.org/mat/1.5/update-site/
            
    栈配置
        java虚拟机提供了参数-Xss来指定线程的最大栈空间,整个参数也直接决定了函数可调用的最大深度
        //-Xss1m  //-Xss5m

    方法区
        和java堆一样,方法区一块所有线程共享的内存区域,他用于保存系统的类信息,方法区(永久区)
            可以保存多少信息可以对其进行配置,在默认情况下,-XX:MaxPermSize为64MB,如果系统运行
            时产生大量的类,就需要设置一个相对和合适的方法区,以免出现永久区内存溢出的问题
            -XX:PermSize=64M -XX:MaxPerSize=64M
            
    直接内存配置
        直接内存也是java程序中非常重要的部分,特别是在NIO中,直接内存跳过了java堆,是java程序可以
            直接访问原生堆空间,因此在一定程度上加快了内存空间的访问速度。但是说直接内存一定就可以
            提高内存访问速度也不见得
        
        相关配置参数:-XX:MaxDirectMemorySize,如果不设置默认值为最大堆空间,即-Xmx。直接内存使用
            达到上限时,就会触发垃圾回收,如果不能有效的释放空间,也会引起系统的OOM
            
    jvm不错的博客
        http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
    
    垃圾收集算法
        引用计数法:这个是比较古老而经典的垃圾收集算法,其核心就是在对象被其他所引用时计数器加1,
            而当引用失效时则减1,但是这种方式有非常严重的问题:无法处理循环引用的情况,还有就是
            每次进行加减操作比较浪费系统性能。
            
        标记清除法:就是分为标记和清除两个阶段进行处理内存中的对象,当然这种方式也有非常大的弊端,
            就是空间碎片问题,垃圾回收后的空间不是连续的,不连续的内存空间的工作效率要低于连续的内存空间
        
        ☆复制算法:其核心思想就是将内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用
            的内存中的存留对象复制到未被使用的内存块中去,之后去清除之前正在使用的内存块中所有的
            对象,反复去交换两个内存的角色,完成垃圾收集。(Java中新生代的from和to空间就是使用这个算法)
            
        ☆标记压缩法:标记压缩法在标记清除法基础之上做了优化,把存活的对象压缩到内存一端,而后进行垃圾清理。
            (java中老年代使用的就是标记压缩法)
        
        ☆分代算法:就是根据对象的特点把内存分成N块,而后根据每个内存的特点使用不同的算法
        对于新生代和老年代来说,新生代回收频率很高,但是每次回收耗时都很短,而老年代回收频率较低,但是耗时
            会相对较长,所以应该尽量减少老年代的GC。
        
        ☆分区算法:其主要就是将整个内存分为N多个小的独立空间,每个小空间都可以独立使用,这样细粒度的控制一次
            回收都少个小空间和那些小空间,而不是对整个空间进行GC,从而提升性能,并减少GC的停顿时间。

    垃圾回收时的停顿现象
        垃圾回收器的任务是识别和回收垃圾对象进行内存清理,为了让垃圾回收器可以高效的执行,大部分情况下,会要求
            系统进入一个停顿的状态,停顿的目的是终止所有应用线程,只用这样系统才不会有新的垃圾产生,同时停顿
            保证了系统状态在某一瞬间的一致性,也有益于更好地标记垃圾对象。因此在垃圾回收时,都会产生应用程序的停顿
    
    对象如何进入老年代
        对象首次创建会被放置在新生代的eden区,如果没有GC接入,对象不会离开eden区,只要对象的年龄达到一定的大小,就会
            自动离开年轻代进入老年代,对象年龄是由对象经历数次GC决定的,在新生代每次GC之后如果对象没有被回收则年龄
            加一,虚拟机提供了一个参数来控制新生代对象的最大年龄,但超过这个年龄就会进入老年代
        -XX:MaxTenuringThreshold = 15,默认情况下为15
        
        大对象(新生代eden区无法装入时,也会直接进入老年代)。JVM中有个参数可以设置对象的大小超过指定大小之后,直接
            进入老年代。  -XX:PretenureSizeThreshold=1024000
            
        虚拟机对于体积不大的数据会优先把数据分配到TLAB区域中,因此就失去了在老年代分配的机会
        
        TLAB全称是Thread Local Allocation Buffer 即线程本地分配缓存,从名字上看是一个线程专用的内存分配区域,是为了
            加速对象分配而生的。每一个线程都会产生一个TLAB,改线程独享的工作区域,java虚拟机使用这种TLAB区来避免多线程
            冲突问题,提高了对象分配的效率,TLAB空间不会太大,当大对象无法再TLAB分配时,则会直接分配到堆上。
            
        -XX:+UseTLAB 使用TLAB
        -XX:+TLABSize 设置TLAB大小
        -XX:+TLABRefillWasteFraction 设置维护进入TLAB空间的单个对象大小,他是一个比例值,默认为64,即如果对象大于整个
            空间的1/64,则在堆创建对象
        -XX:+PrintTLAB 查看TLAB信息
        -XX:Resize TLAB 自调整TLABRefillWasteFraction阀值
        
    垃圾收集器
        串行垃圾回收器:使用单线程进行垃圾回收的回收器,每次回收时,串行回收器只有一个工作线程,对于并行能力较弱的
            计算机来说,串行回收器的专注性和独占性往往有更好的性能表现,串行回收器可以在新生代和老年代使用,根据作用
            用于不同的堆空间,分为新生代串行回收器和老年代串行回收器。
            使用-XX:+UseSerialGC参数可以设置使用新生代串行回收器和老年代串行回收器
            
        并行垃圾回收器:在串行的基础上做了改进,可以使用对个线程同时进行垃圾回收,对于计算能力强的计算机而言,可以
            有效的缩短垃圾回收所需的实际时间。
            
            parNew回收器是一个工作在新生代的垃圾回收器,他只是简单的将串行回收器多线程化,他的回收策略和算法和串行回收器一样
            使用-XX:+UseParNewGC新生代ParNew回收器,老年代则使用串行回收器ParNew回收器工作时的线程数量可以使用
            -XX:ParallerlGCThreads参数指定,一般最好和计算机的CPU相当,避免过多的线程影响性能。
            
            新生代ParallelGC回收器,使用了复制算法端的收集器,也是多线程独占形式的收集器,但ParaellGC回收器有个非常重要
                的特点,就是他非常关注系统的吞吐量
                -XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间
                -XX:GCTimeRatio:设置吞吐量大小,是一个0到100之间的整数
                -XX:+UseAdaptiveSizePolicy:打开自适应模式
                
            老年代ParallelOldGC回收器也是一种多线程的回收器,和新生代的ParallelGC回收器一样,也是一种关注吞吐量的
                回收器,他使用了标记压缩算法进行实现
            -XX:+UseParallelOldGC进行设置
            -XX:+ParallelGCThreads 也可以设置垃圾收集时的线程数量
            
        CMS垃圾回收器
            Concurrent Mark Sweep意为并发标记清楚,他是用的是标记清出法,主要关注系统停顿时间
            使用-XX:UseConcMarkSweepGC 进行设置
            使用-XX:ConcGCThreads 设置并发线程数量
            
            CMS并不是独占回收器,也就是说CMS回收过程中,应用程序仍然在不停的工作,又会有新的垃圾不断产生,所以在使用
                CMS垃圾回收器的过程中应该确保应用程序的内存足够使用,CMS不会等到应用程序饱和的时候才去回收垃圾,而是
                在某一阀值的时候开始回收,回收阀值可用指定的参数进行配置。-XX:CMSInitiatingOccupancyFraction来指定,
                默认为68,也就是说当老年代的空间使用录达到68%的时候,会执行CMS回收,如果内存使用率增长很快,在CMS执行
                的过程中,已经出现了内存不足的情况,此时CMS回收就会失败,虚拟机将启动老年代串行回收器进行垃圾回收,这
                会导致应用程序中断,直到垃圾回收完成后才会正常工作,这个过程GC的停顿时间可能较长,所以
                -XX:CMSInitiatingOccupancyFraction的设置要根据实际情况。
                
            之前我们在学习算法的时候说过,标记情出发有个缺点就是存在内存碎片的问题,那么CMS有个参数设置
                -XX:+UseCMSCompactAtFullCollecion可以使CMS回收完成之后进行一次碎片整理,
                -XX:CMSFullGCsBeforeCompaction参数可以设置进行多少次回收之后,对内存进行一次压缩
                
        G1回收器
            在jdk 1.7 中提出的垃圾回收器,从长期目标看是为了取代CMS回收器,G1回收器拥有独特的垃圾回收策略,G1属于分代
                垃圾回收器,区分新生代和老年代,依然有eden和from/to区,他并不要求整个eden区或者新生代、老年代的空间
                都连续,他是用了分区算法。
            并发性:G1回收期间可多线程同时工作
            并发性:G1会有与应用程序假体执行的能力,部分工作可与应用程序同时执行,在整个GC期间不会完全阻塞应用程序
            分代GC:G1依然是一个分代的收集器,但是他是兼顾新生代和老年代一起工作,之前的垃圾回收器他们或者在新生代
                或者在老年代工作。因此这个一个很大的不同
            空间整理:G1在回收的过程中,不会像CMS那样在若干次GC后需要进行碎片整理,G1采用了有效的复制对象的方式,减少空间碎片
            可预见性:由于分区的原因,G1可以在选取部分区域进行回收,缩小了回收的范围,提升了性能。
            使用 -XX:+UseG1GC 应用G1收集器
            使用 -XX:MaxGCPauseMillis 指定最大停顿时间
            使用 -XX:ParallelGCThreads 设置并行回收的线程数量
            
    测试串行回收器
        -XX:+PrintGCDetails -Xmx32M -Xms32M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseSerialGC
        -XX:PermSize=32M
        测试结果显示吞吐量为:1152 115
        
    扩大堆内存以提升系统性能
        -XX:+PrintGCDetails -Xmx512M -Xms32M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseSerialGC
        -XX:PermSize=32M
        -Xloggc:d:/gc.log
        测试结果显示吞吐量为:1557 155
        
    调整初始堆大小
        -XX:+PrintGCDetails -Xmx512M -Xms128M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseSerialGC
        -XX:PermSize=32M
        -Xloggc:d:/gc.log
        测试结果显示吞吐量为:2100 209
        
    测试ParNew回收器的表现
        -XX:+PrintGCDetails -Xmx512M -Xms128M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseParNewGC
        -XX:PermSize=32M
        -Xloggc:d:/gc.log
        测试结果显示吞吐量为:2200 220
        
    使用ParallelOldGC回收器(最高的)
        -XX:+PrintGCDetails -Xmx512M -Xms128M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseParNewGC
        -XX:+UseParNewOldGC
        -XX:ParallelGCThreads=8
        -XX:PermSize=32M
        -Xloggc:d:/gc.log
        测试结果显示吞吐量为:3336 330
        
    测试CMS回收器的性能
        -XX:+PrintGCDetails -Xmx512M -Xms128M
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:+UseConcMarkSweepGC
        -XX:ConcGCThreads=8
        -XX:PermSize=32M
        -Xloggc:d:/gc.log
        测试结果显示吞吐量为:2100 209
        
       
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值