JVM调优.pdf

所需积分/C币:50 2017-08-10 13:30:40 1.13MB PDF
107
收藏 收藏
举报

JVM调优 调优参数 调优方法 , 调优手段 等.
小就值得商榷 在Java中,一个空 Object对象的大小是8byte,这个大小只是保存堆中一个没有任何属 性的对象的大小。看下面语句: Object ob =new objecto 这样在程序中完成了个Java对象的生命,但是它所占的空间为:4byte+8byte。4byte 是上面部分所说的Java栈中保存引用的所需要的空间。而那8byte则是Java堆中对象的 息。因为所有的Java非基本类型的对象都需要默认继承 Object对象,因此不论什么样的Java 对象,其大小都必须是大于8byte 有了 Object对象的大小,我们就可以计算其他对象的大小了 Class Newobject int count: boolean fl object ob 其大小为:空对象大小(8byte+int大小4byte)+ Boolean大小(1byte)+空 object引用的大小 (4byte)=17byte但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte 的最接近8的整数倍的是24,因此此对象的大小为24byte。 这里需要注意一下基本类型的包装类型的大小。因为这种包装类型经成为对象了,因 此需要把他们作为对象来看待。包装类型的人小至少是12byte(声明一个空 Object至少需 要的空间),而且12bye没有包含任何有效信息,同时,因为Java对象大小是8的整数倍, 因此一个基本类型包装类的大小至少是16byte。这个内存占用是很恐怖的,它是使用基本 类型的N倍(N>2),有些类型的内存占用更是夸张(随便想下就知道了)。因此,可能的话 应尽量少使用包装类。在JDK5.0以后,因为加入了自动类型装换,因此,Java虚拟机会在 存储方面进行相应的优化。 引用类型 对象引用类型分为强引用、软引用、弱引用和虚引用。 强引用:就是我们般声明对象是吋虚拟机生成的引用,强引用环境下,垃圾回收吋需要严 柊判断当前对象是否被强引用,如果被强引用,则不会被垃圾回收 软引用:软引用一般被做为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机 会根椐当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟 机会回收软引用所引用的空间;如果剩余內存相对富裕,则不会进行回收。换句话说,虚拟 机在发生 OutOfMemory时,青定是没有软引用存在的。 弱引用:弱引用与软引用类似,都是作为缓存来使用。但与软引用不同,弱引用在进行垃圾 回收时,是一定会被回收掉的,因此其生命周期只存在于一个垃圾回收周期内。 强引用不用说,我们系统一般在使用时都是用的强引用。而“软引用”和〃弱引用”比较少见。 他们一般被作为缓存使用,而且一般是在内存大小比较受限的情況下做为缓存。因为如果内 存足够大的话,可以直接使用强引用作为缓存即可,同吋可控性更高。因而,他们常见的是 被使用在桌面应用系统的缓存。 可以从不同的的角度去划分垃圾回收算法: 按照基本回收策略分 引用计数( Reference Counting) 比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一 个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问 题 标记-清除( Mark-Sweep): Before GC After GC 此算法执行分两阶段。第ˉ阶段从引用根节点开始标记所有被引用的对象,第阶段遍历整 个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。 复制( Copying): Before gc After GC 此算法把内存空间划为两个相等的区域,每次只使用其中·个区域。垃圾回收吋,遍历当前 使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对 象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片〃 问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。 标记整理( Mark-Compact): Before gc After GC 此算法结合了“标记清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始 标记所冇被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象压缩″到堆 的其中一块,按顺序排放。此算法避免了“标记清除″的碎片问题,同时也避免了“复制算法 的空间问题。 按分区对待的方式分 增量收集( Incremental Collecting):实时垃圾冋收算法,即:在应用进行的冋时进行垃圾冋 收。不知道什么原因JDK5.0中的收集器没有使用这种算法的。 分代收集( Generational Collecting):基于对对象生命周期分析后得出的垃圾回收算法。把对 象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一 个)进行回收。现在的垃圾回收器(从』SE1.2开始)都是使用此算法的 按系统线程分 串行收集:串行收集使用单线程处理所有垃圾回收工作,因为无需多线程父互,实现容易, 而且效率比较高。但是,其局限性也比较明显,即无法使用多处理器的优势,所以此收集适 合单处理器机器。当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机 器上。 并行收集:并行收集使用多线程处理垃圾冋收工作,因而速度快,效率高。而且理论上CPU 数目越多,越能体现出并行收集器的优势。 并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整 个运行环境,而只有垃圾回收程序在运行,因此,系统在垃圾回收时会有明显的暂停,而且 暂停时间会因为堆越大而越长 如何区分垃圾 上面说到的〃引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回 收程序收集计数为O的对象即可。但是这种方法无法解决循环引用。所以,后来实现的垃圾 判断算法中,都是从程序运行的根节点出发,遍历整个对象引用,查找存活的对象。那么在 这种方式的实现中,垃圾回收从哪儿开始的呢?即,从哪儿开始查找哪些对象是正在被当前 系统使用的。上面分析的堆和栈的区别,其中栈是真止进行程序执行地方,所以要获取哪些 对象正在被使用,则需要从Java栈开始。同时,一个栈是与一个线程对应的,因此,如果 有多个线程的话,则必须对这些线程对应的所有的栈进行检查。 Root Objects Heap stack static field local var 同时,除了栈外,还有系统运行时的寄存器等,也是存储程序运行数据的。这样,以栈 或寄存器中的引用为起点,我们可以找到堆中的对象,又从这些对象找到对堆中其他对象的 引用,这种引用逐步扩展,最终以nu引用或者基本类型结束,这样就形成了一颗以Java 栈中引用所对应的对象为根节点的颗对象树,如果栈中有多个引用,则最终会形成多颗对 象树。在这些对象树上的对象,都是当前系统运行所需要的对象,不能被垃圾回收。而其他 剩余对象,则可以视为无法被引用到的对象,可以被当倣垃圾进行回收 因此,垃圾回收的起点是一些根对象(java栈,静态变量,寄存器…)。而最简单的Java栈就 是Java程序执行的man函数,这种回收方式,也是上面提到的“标记清除”的回收方式 如何处理碎片 由于不同Java对象存活时是不一定的,因此,在程序运行一段时间以后,如果不进行 内存整理,就众出现零散的内有碎片。碎片最直接的问题就是众导致无法分配人块的内存空 间,以及程序运行效率降低。所以,在上面提到的基本垃圾回收算法中,“复制〃方式和“标 记-整理”方式,都可以解决碎片的问题。 如何解决同时存在的对象创建和对象回收问题 垃圾回收线程是回收内存的,而程序运行线程则是消耗(或分配)内存的,一个回收内 存,一个分配内存,从这点看,两者是矛盾的。因此,在现有的垃圾回收方式中,要进行垃 圾冋收前,一般都需要暂停整个应用(即:暂停内存的分配),然后进行垃圾冋收,冋收完 成后再继续应用。这种实现方式是最直接,而且最有效的解决二者矛盾的方式。 但是这种方式有一个很明显的弊端,就是当堆空间持续增大时,垃圾回收的时间也将会相 应的持续增大,对应应用暂停的时间也会相应的增大。一些对相应时间要求很高的应用, 比如最大暂停时间要求是几百毫砂,那么当堆空间大于几个G时,就很有可能超过这个限 制,在这种情况下,垃圾回收将会成为系统运行的一个瓶颈。为解决这种矛盾,有了并发垃 圾回收算法,使用这种算法,垃圾回收线程与程序运行线程同时运行。在这种方式下,解决 了暂停的门遨,但是因为需要在新生成对象的冋时又要回收对象,算法复杂性会大大增加, 系统的处理能力也会相应降低,同时,“碎片”问题将会比较难解决。 为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此 不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。 在」ava程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如 Htp请求中的 Session对象、线程、 Socket连接,这类对象跟业务直接挂钩,因此生命周期 比较长。但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会 比较短,比如: String对象,由于其不变类的特性,系统会产牛人量的这些对象,有些对象 甚至只用次即可回收 试想,在不进行对象存活时间区分的情况下,每次垃圾冋收都是对整个堆空间进行冋收 花费时间相对会长,同时,因为每次回收都需要遍历所有存活对象,但实际上,对」生命周 期长的对象而言,这种煸历是没有效果的,因为可能进行了很多次遍历,但是他们依旧存在。 因此,分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上 不同代上采用最适合它的垃圾回收方式进行回收 如何分代 CInit Obj Alloc,-- Survivor ratio Eden Space From To Space Space Young generation Tenured space Old Generation Permanent Space Permanent Generation 如图所示: 虚拟机中的共划分为三个代:年轻代( Young Generation)、年老点( old generation)和 持久代( Permanent generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集 要收集的Java对象关系不大。年轾代和年老代的划分是对垃圾收集影响比较大的。 年轻代: 所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集护那些 生命周期短的对象。年轻代分三个区。一个Eden区,两个 Survivor区(一般而言)。大部分对 象在Eden区中生成。当Eden区满时,还存活的对象将被复制到 Survivor区(两个中的一个), 当这个 Survivor区满时,此区的存活对象将被复制到另外一个 Survivor区,当这个 Survivor 去也满了的时候,从第一个 Survivor区复制过来的并且此时还存活的对象,将被复制“年老 区( Tenured”。需要注意, Survivor的两个区是对称的,没先后关系,所以同个区中可能同 时存在从Eden复制过来对象,和从前一个 Survivor复制过来的对象,而复制到年老区的只 有从第一个survⅳor去过来的对象。而且, Surviⅳor区总有一个是空的。同时,根据程序需 要,Survⅳor区是可以蓖置为多个的(多」两个),这样可以增加对象在年轻代中的存在时 间,减少被放到年老代的可能。 年老代: 在年轻代中经历了N次垃圾冋收后仍然存活的对象,就会被放到年老代中。因此,可以 认为年老代中存放的都是一些生命周期较长的对象 持久代 用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些 应用可能动态生成或者调用一些clas,例如 Hibernate等,在这种时候需要设置一个比较大 的持久代空间来存放这些运行过程中新增的类。持久代大小通过 XX. Max PermSize=<N进行 设置 什么情况下触发垃圾回收 由于对象进行了分代处理,因此垃圾冋收区域、时间也不一样。GC有两和类型: Scavenge GC和FuGC。 Scavenge gc 般情况下,当新对象生成,并且在Eden卬请空冋失败时,就会蝕发 Scavenge GC,对 Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到 Survivor区。然后整理 Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大 部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁 进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。 Full gc 对整个堆进行整理,包括 Young、 Tenured和Perm。FuGC因为需要对整个对进行回收, 所以比 Scavenge GC要慢,因此应该尽可能减少Fu!GC的次数。在对ⅳM调优的过程中, 很大一部分工作就是对于FuGC的调节。有如下原因可能导致FuGC: 年老代( Tenured)被写满 持久代(Perm)被写满 System.gc()被显示调用 ·上一次GC之后Heap的各域分配策略动态变化 分代垃圾回收流程示意 axT Eden From To NEW Fromto From To NEW From To NEW ‖H|RcT NEW Eden TO NEW NEW To NEW

...展开详情
试读 28P JVM调优.pdf
立即下载
限时抽奖 低至0.43元/次
身份认证后 购VIP低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
上传资源赚钱or赚积分
最新推荐
JVM调优.pdf 50积分/C币 立即下载
1/28
JVM调优.pdf第1页
JVM调优.pdf第2页
JVM调优.pdf第3页
JVM调优.pdf第4页
JVM调优.pdf第5页
JVM调优.pdf第6页

试读结束, 可继续读3页

50积分/C币 立即下载