JVM调优总结

合集下载

记一次JVMFullGC(MetadataGCThreshold)调优经历

记一次JVMFullGC(MetadataGCThreshold)调优经历

记⼀次JVMFullGC(MetadataGCThreshold)调优经历记⼀次JVM Full GC (Metadata GC Threshold)调优经历⼀、背景:线上服务器内存使⽤超过90%,分析上⾯部署的各个服务的GC⽇志,发现有⼀个服务的JVM内存分配过⼤,使⽤率较低,有调优的空间,可以在不迁移服务或者不升级服务器配置的情况下,降低服务器内存占⽤。

JVM推荐配置原则:应⽤程序运⾏时,计算⽼年代存活对象的占⽤空间⼤⼩X。

程序整个堆⼤⼩(Xmx和Xms)设置为X的3 ~ 4倍;永久代PermSize和MaxPermSize设置为X的1.2 ~ 1.5倍。

年轻代Xmn的设置为X的1 ~ 1.5倍。

⽼年代内存⼤⼩设置为X的2 ~ 3倍。

JDK官⽅建议年轻代占整个堆⼤⼩空间的3/8左右。

完成⼀次Full GC后,应该释放出70%的堆空间(30%的空间仍然占⽤)。

观察线上发现2G的堆内存,Full GC之后的活跃对象才占⽤60M。

按照推荐设置JVM内存只需要给⼏百M就好了。

所以决定改成1G,既能够降低服务器内存占⽤,也预留了⾜够的业务增长空间。

在这个过程中,发现如下⼏个问题:GC⽇志没有时间显⽰,看起来很不⽅便GC⽇志没有滚动,时间久了,⽇志⽂件较⼤GC⽇志中存在⼤量Full GC (Metadata GC Threshold)显然第三个问题最为严重。

我们知道,元数据区主要是⽤来存储类的元数据的。

⼀般来讲,类加载完成之后,⼤⼩应该是⽐较稳定的,不会有太⼤变动。

所以可以判断,这么频繁的Full GC (Metadata GC Threshold),肯定是哪⾥出问题了。

但是我们⼀步⼀步来解决问题,⽽且GC⽇志不够详细也影响我们定位问题。

⼆、优化GC⽇志打印⾸先复习⼀下JVM的GC⽇志打印的启动参数。

详见-verbose:gc同-XX:+PrintGC-XX:+PrintGC最简单的 GC 参数会打印 GC 前后堆空间使⽤情况以及 GC 花费的时间-XX:+PrintGCDetails打印GC的详细信息,会打印 youngGC FullGC前后堆【新⽣代,⽼年代,永久区】的使⽤情况以及 GC 时⽤户态 CPU 耗时及系统CPU 耗时及 GC 实际经历的时间-XX:+PrintGCTimeStamps打印CG发⽣的时间戳,从应⽤启动开始累计的时间戳-XX:+PrintGCDateStamps打印GC发⽣的时刻,所处⽇期时间信息-Xloggc:gc.log指定GC log的位置,以⽂件输出-XX:+PrintHeapAtGC每⼀次GC前和GC后,都打印堆信息。

深入分析JVM的优点与缺点

深入分析JVM的优点与缺点

深入分析JVM的优点与缺点JVM(Java虚拟机)是一种在计算机上运行Java字节码的虚拟机,它具有许多优点和一些缺点。

本文将深入分析JVM的优势和不足之处,具体如下:优点:1. 跨平台性:JVM是为Java程序设计语言而创建的虚拟机,可以在不同的操作系统上运行Java程序,无需重新编写或修改代码。

这种跨平台性使得Java成为一种非常流行的编程语言。

2.内存管理:JVM提供了自动内存管理,通过垃圾回收器自动处理内存分配和释放,这样程序员就不需要手动管理内存,减轻了开发人员的负担并且避免了常见的内存泄漏和溢出问题。

3.安全性:通过安全沙箱机制,JVM可以在程序执行期间限制程序对底层系统资源的访问。

这样可以防止恶意软件和病毒对计算机的破坏,提高了安全性。

4. 高可移植性:由于JVM的跨平台性,Java程序一旦在一个平台上编写和测试完成,就可以在其他平台上运行,无需重新编写和调试代码。

5. 高性能:尽管Java是解释型语言,但JVM使用即时编译器(JIT)将Java字节码直接编译成机器码,从而提高了程序的执行效率。

JIT编译器可以对热点代码进行优化,提供接近于本地代码执行的性能。

不足之处:1.内存消耗:JVM启动和运行需要占用较大的内存,而且由于垃圾回收机制,JVM的内存占用也较高。

在一些资源有限的环境中,这可能导致问题。

2. 执行速度:虽然JIT编译器可以提高Java程序的执行速度,但与本地代码相比,Java程序的执行速度仍然较慢。

这一点在对实时性要求较高的应用程序中可能会成为问题。

3.配置复杂性:由于JVM的各种配置选项和优化参数较多,使得调优和优化JVM变得复杂。

不正确的配置可能导致性能下降或其他问题。

4.学习成本:相对于其他编程语言和平台,学习和理解JVM的工作原理和内部机制可能需要更多的时间和精力。

5. 移植性限制:尽管JVM使得Java程序具有高度可移植性,但一些情况下,特定平台的限制或特性可能会对Java程序的移植性产生一些限制。

java性能调优的基本知识

java性能调优的基本知识

Java堆是指在程序运行时分配给对象生存的空间。

通过-mx/-Xmx和-ms/-Xms来设置起始堆的大小和最大堆的大小。

根据自己JDK的版本和厂家决定使用-mx和-ms或-Xmx和-Xms。

Java堆大小决定了垃圾回收的频度和速度,Java堆越大,垃圾回收的频度越低,速度越慢。

同理,Java堆越小,垃圾回收的频度越高,速度越快。

要想设置比较理想的参数,还是需要了解一些基础知识的。

Java堆的最大值不能太大,这样会造成系统内存被频繁的交换和分页。

所以最大内存必须低于物理内存减去其他应用程序和进程需要的内存。

而且堆设置的太大,造成垃圾回收的时间过长,这样将得不偿失,极大的影响程序的性能。

以下是一些经常使用的参数设置:1) 设置-Xms等于-XmX的值;2) 估计内存中存活对象所占的空间的大小,设置-Xms等于此值,-Xmx四倍于此值;3) 设置-Xms等于-Xmx的1/2大小;4) 设置-Xms介于-Xmx的1/10到1/4之间;5) 使用默认的设置。

大家需要根据自己的运行程序的具体使用场景,来确定最适合自己的参数设置。

除了-Xms和-Xmx两个最重要的参数外,还有很多可能会用到的参数,这些参数通常强烈的依赖于垃圾收集的算法,所以可能因为JDK的版本和厂家而有所不同。

但这些参数一般在Web 开发中用的比较少,我就不做详细介绍了。

在实际的应用中注意设置-Xms和-Xmx使其尽可能的优化应用程序就行了。

对于性能要求很高的程序,就需要自己再多研究研究Java虚拟机和垃圾收集算法的机制了。

可以看看曹晓钢翻译的《深入Java虚拟机》一书。

Java程序性能调优的基本知识和JDK调优一基本知识1.1 性能是什么在性能调优之前,我们首先来了解一下性能是什么?关于性能,我想每个学习过Java的人都能列出几点,甚至可以夸夸其谈。

在《Java TM Platform Performance》一书中,定义了如下五个方面来作为评判性能的标准:1) 运算的性能——哪一个算法的执行性能最好?2) 内存的分配——程序运行时需要耗费多少内存?3) 启动的时间——程序启动需要多长时间?这在Web项目中的影响不大,但要注意部分程序需要部署或运行在客户端时的情形(比如applet程序)。

JVM内存设置方法

JVM内存设置方法

JVM内存设置方法JVM(Java虚拟机)是Java程序的运行环境,它负责执行Java字节码,并管理程序的内存。

在运行Java程序时,合理地设置JVM的内存大小是非常重要的,它会影响程序的性能和稳定性。

下面是一些关于JVM内存设置的方法和注意事项:1. 初始堆大小(-Xms)和最大堆大小(-Xmx):初始堆大小指定了JVM初始时分配的堆内存大小,最大堆大小则指定了堆内存的上限。

可以通过在启动命令中加上-Xms和-Xmx参数来设置堆内存大小,例如:```java -Xms256m -Xmx512m MyApp```这样就设置了初始堆大小为256MB,最大堆大小为512MB。

2.堆内存的大小选择:堆内存的大小应根据应用程序的需求和服务器硬件条件来选择。

如果堆内存过小,可能会导致OutOfMemoryError;如果堆内存过大,可能会导致频繁的垃圾回收,影响程序的性能。

可以通过监控JVM的堆使用情况来判断是否需要调整堆内存的大小。

可以使用JVM自带的JVisualVM工具或第三方的工具如G1GC日志分析工具进行监控。

3.堆内存的分代设置:堆内存分为新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation,JDK8及之前的版本)/元空间(Metaspace,JDK8及之后的版本)。

新生代用于存储新创建的对象,老年代用于存储长时间存活的对象,永久代/元空间用于存储类和方法等信息。

可以通过设置堆内存的分代比例来调整堆内存的大小,例如:```-XX:NewRatio=2```这样就将堆内存的新生代和老年代的大小比例设置为1:2、可以根据应用程序的特点和需求进行调整。

4.非堆内存的设置:非堆内存包括方法区、直接内存等。

可以通过设置参数来调整非堆内存的大小,例如:```-XX:MaxMetaspaceSize=256m```这样就设置了元空间的最大大小为256MB。

《Java性能调优指南》

《Java性能调优指南》

《Java性能调优指南》随着互联网的飞速发展,Java作为一种重要的编程语言,被越来越广泛地应用于各个领域。

但是,Java程序的性能问题也随之出现。

如何调优Java 程序的性能,成为了每个开发人员需要解决的难题。

本文将为大家介绍Java性能调优的指南。

一、JVM参数设置JVM(Java虚拟机)参数设置是Java性能调优的关键。

JVM有众多的参数,不同的参数设置会对Java程序的性能产生不同的影响。

常用的JVM参数设置包括以下几个方面:1. 内存设置内存是Java程序的一大瓶颈。

如果内存设置不合理,会导致Java程序频繁地进行垃圾回收,造成程序的延迟和不稳定。

在设置内存参数时需要注意以下几点:- -Xmx: 最大堆内存,设置合理的最大堆内存大小可以减少JVM的垃圾回收次数,提高程序性能。

- -Xms: 初始堆内存,设置合理的初始堆内存大小可以加快程序启动时间,提高程序性能。

- -XX:NewRatio: 新生代与老年代的比例,如果设置得当,可以减少垃圾回收的次数。

通常新生代的大小为总堆容量的1\/3或1\/4,老年代的大小为总堆容量的2\/3或3\/4。

2. 垃圾回收设置垃圾回收是Java程序中必不可少的一部分。

合理的垃圾回收参数设置可以提高程序性能。

常用的垃圾回收参数设置包括以下几点:- -XX:+UseParallelGC: 使用并行GC,适用于多核CPU。

- -XX:+UseConcMarkSweepGC: 使用CMS GC,适用于大型Web应用程序。

- -XX:+UseG1GC: 使用G1 GC,适用于大内存应用程序。

3. JIT设置JIT(即时编译器)是Java程序中非常重要的一部分。

合理的JIT参数设置可以提高程序的性能。

常用的JIT参数设置包括以下几点:- -XX:+TieredCompilation: 启用分层编译,可以提高程序启动时间和性能。

- -XX:CompileThreshold: JIT编译阈值,设置JIT编译的最小方法调用次数,可以提高程序性能。

ava优化知识点总结

ava优化知识点总结

ava优化知识点总结一、Java内存优化1. 内存泄漏内存泄漏是指程序在动态分配内存时,由于某种原因(例如程序中有一些指针指向动态分配的内存,但程序没有释放这些内存,这样就会导致内存的浪费)而不能归还内存,使得程序持续占用着内存而无法释放的现象。

解决内存泄漏的方法:- 使用JVM内存分析工具,如jmap、jstat、jconsole等来检测内存泄漏;- 使用代码审查工具检查程序是否存在内存泄漏;- 关注对象的生命周期,及时释放不再使用的对象,避免长时间持有对象的引用。

2. 垃圾回收垃圾回收是Java内存管理的一部分,用于回收不再使用的对象,释放内存空间。

垃圾回收器通过不断扫描堆中的对象,标记哪些对象是活动的,然后释放那些不再被引用的对象。

优化垃圾回收的方法:- 合理设计对象的生命周期,避免对象产生过多的引用;- 使用合适的垃圾回收器,合理的调整堆空间大小,以及调整垃圾回收器的触发机制;- 使用轻量级对象池,重复利用对象,减少垃圾回收的次数。

3. 字符串拼接在Java中,字符串是不可变的,当进行字符串拼接时,会产生很多临时对象,会导致内存的浪费。

可以使用StringBuilder或StringBuffer来提高性能,避免产生大量的临时对象。

优化字符串拼接的方法:- 使用StringBuilder或StringBuffer来进行大量的字符串拼接;- 使用字符串常量池,避免产生重复的字符串对象;- 使用StringJoiner类来进行字符串的拼接。

二、Java性能调优1. 数据结构的选择在实际开发中,选用合适的数据结构对程序性能至关重要。

不同的数据结构适用于不同的场景,可以根据实际情况选择合适的数据结构,提高程序性能。

常用的数据结构优化方法:- 数组:适用于数据量固定、访问频繁的场景;- 链表:适用于频繁插入和删除操作的场景;- 树:适用于有层次关系的场景;- 哈希表:适用于快速查找的场景。

2. 多线程的优化多线程是提高系统性能的一种方法,同时也是一把双刃剑,要想合理利用多线程提高性能,需要考虑线程安全、死锁等问题。

jvm常用调优参数

jvm常用调优参数

jvm常用调优参数
JVM是JavaVirtualMachine的缩写,是Java程序运行的核心。

JVM的调优是优化Java应用程序性能的重要一环,其中调优参数的合理设置是关键。

以下是常用的JVM调优参数:
1. -Xms:设置JVM的初始内存大小,默认为物理内存的
1/64。

2. -Xmx:设置JVM的最大内存大小,超出该内存大小后会触发垃圾回收。

3. -Xmn:设置年轻代的大小,一般设置为总内存的1/3或
1/4。

4. -XX:SurvivorRatio:设置年轻代中Eden区和Survivor区的比例,默认值为8。

5. -XX:NewRatio:设置新生代和老年代的比例,默认值为2。

6. -XX:MaxPermSize:设置永久代的大小,一般设置为
256MB。

7. -XX:+UseConcMarkSweepGC:使用CMS垃圾回收器,可以减少内存抖动。

8. -XX:+UseParallelGC:使用并行垃圾回收器,可提高垃圾回收效率。

9. -XX:+HeapDumpOnOutOfMemoryError:当JVM内存溢出时,生成堆转储文件。

10. -XX:+PrintGCDetails:打印垃圾回收的详细信息。

以上是常用的JVM调优参数,通过合理地设置参数,可以优化Java应用程序的性能。

JVM调优总结

JVM调优总结

JVM调优总结作者: 和你在一起程序员其实很痛苦的,每隔一段时间就会听到、看到很多很多新名词、新技术---囧.幸而有了互联网,有了开源、有了wiki、有了分享:)—人人为我,我为人人。

拓荒者走过的时候很痛苦,但是如果能给后来人留下点路标,是不是可以让他们少走一些弯路呢?踏着前辈的足迹我走到了这里,也应该为后来的人留下点东西。

走夜路其实不可怕,可怕的是一个人走夜路:) - 做最棒的软件开发交流社区A-PDF Number Pro DEMO: Purchase from to remove the watermark目 录1. java路上1.1 JVM调优总结-序 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 1.2 JVM调优总结(一)-- 一些概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 1.3 JVM调优总结(二)-一些概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7 1.4 JVM调优总结(三)-基本垃圾回收算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9 1.5 JVM调优总结(四)-垃圾回收面临的问题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 1.6 JVM调优总结(五)-分代垃圾回收详述1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14 1.7 JVM调优总结(六)-分代垃圾回收详述2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18 1.8 JVM调优总结(七)-典型配置举例1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26 1.9 JVM调优总结(八)-典型配置举例2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 1.10 JVM调优总结(九)-新一代的垃圾回收算法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .34 1.11 JVM调优总结(十)-调优方法 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .38 1.12 JVM调优总结(十一)-反思 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .47 1.13 JVM调优总结(十二)-参考资料 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .501.1 JVM调优总结-序发表时间: 2009-11-17几年前写过一篇关于JVM调优的文章,前段时间拿出来看了看,又添加了一些东西。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

JVM调优总结(一)-- 一些概念数据类型Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。

基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。

―引用值‖代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。

基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress引用类型包括:类类型,接口类型和数组。

堆与栈堆和栈是程序运行的关键,很有必要把他们的关系说清楚。

栈是运行时的单位,而堆是存储的单位。

栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。

在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。

而堆则是所有线程共享的。

栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。

包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。

为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?第一,从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。

这样分开,使得处理逻辑更为清晰。

分而治之的思想。

这种隔离、模块化的思想在软件设计的方方面面都有体现。

第二,堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。

这种共享的收益是很多的。

一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。

第三,栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。

由于栈只能向上增长,因此就会限制住栈存储内容的能力。

而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。

第四,面向对象就是堆和栈的完美结合。

其实,面向对象方式的程序与以前结构化的程序在执行上没有任何区别。

但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。

当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。

我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。

不得不承认,面向对象的设计,确实很美。

在Java中,Main函数就是栈的起始点,也是程序的起始点。

程序要运行总是有一个起点的。

同C语言一样,java中的Main就是那个起点。

无论什么java程序,找到main就找到了程序执行的入口:)堆中存什么?栈中存什么?堆中存的是对象。

栈中存的是基本数据类型和堆中对象的引用。

一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处:))。

为什么不把基本类型放堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了,如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。

可以这么说,基本类型和对象的引用都是存放在栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。

但是基本类型、对象引用和对象本身就有所区别了,因为一个是栈中的数据一个是堆中的数据。

最常见的一个问题就是,Java中参数传递时的问题。

Java中的参数传递时传值呢?还是传引用?要说明这个问题,先要明确两点:1. 不要试图与C进行类比,Java中没有指针的概念2. 程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。

不会直接传对象本身。

明确以上两点后。

Java在方法调用传递参数时,因为没有指针,所以它都是进行传值调用(这点可以参考C的传值调用)。

因此,很多书里面都说Java是进行传值调用,这点没有问题,而且也简化的C中复杂性。

但是传引用的错觉是如何造成的呢?在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为―传引用值‖的传值调用,即引用的处理跟基本类型是完全一样的。

但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到真正的对象。

如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。

所以这个修改是可以保持的了。

对象,从某种意义上说,是由基本类型组成的。

可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。

程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。

堆和栈中,栈是程序运行最根本的东西。

程序运行可以没有堆,但是不能没有栈。

而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。

不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。

Java中,栈的大小通过-Xss来设置,当栈中存储数据比较多时,需要适当调大这个值,否则会出现ng.StackOverflowError异常。

常见的出现这个异常的是无法返回的递归,因为此时栈中保存的信息都是方法返回的记录点。

JVM调优总结(二)-一些概念Java对象的大小基本数据的类型的大小是固定的,这里就不多说了。

对于非基本类型的Java对象,其大小就值得商榷。

在Java中,一个空Object对象的大小是8byte,这个大小只是保存堆中一个没有任何属性的对象的大小。

看下面语句:这样在程序中完成了一个Java对象的生命,但是它所占的空间为:4byte+8byte。

4byte 是上面部分所说的Java栈中保存引用的所需要的空间。

而那8byte则是Java堆中对象的信息。

因为所有的Java非基本类型的对象都需要默认继承Object对象,因此不论什么样的Java对象,其大小都必须是大于8byte。

有了Object对象的大小,我们就可以计算其他对象的大小了。

其大小为:空对象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小(4byte)=17byte。

但是因为Java在对对象内存分配时都是以8的整数倍来分,因此大于17byte的最接近8的整数倍的是24,因此此对象的大小为24byte。

这里需要注意一下基本类型的包装类型的大小。

因为这种包装类型已经成为对象了,因此需要把他们作为对象来看待。

包装类型的大小至少是12byte(声明一个空Object至少需要的空间),而且12byte没有包含任何有效信息,同时,因为Java对象大小是8的整数倍,因此一个基本类型包装类的大小至少是16byte。

这个内存占用是很恐怖的,它是使用基本类型的N倍(N>2),有些类型的内存占用更是夸张(随便想下就知道了)。

因此,可能的话应尽量少使用包装类。

在JDK5.0以后,因为加入了自动类型装换,因此,Java虚拟机会在存储方面进行相应的优化。

引用类型对象引用类型分为强引用、软引用、弱引用和虚引用。

强引用:就是我们一般声明对象是时虚拟机生成的引用,强引用环境下,垃圾回收时需要严格判断当前对象是否被强引用,如果被强引用,则不会被垃圾回收软引用:软引用一般被做为缓存来使用。

与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。

如果剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。

换句话说,虚拟机在发生OutOfMemory时,肯定是没有软引用存在的。

弱引用:弱引用与软引用类似,都是作为缓存来使用。

但与软引用不同,弱引用在进行垃圾回收时,是一定会被回收掉的,因此其生命周期只存在于一个垃圾回收周期内。

强引用不用说,我们系统一般在使用时都是用的强引用。

而―软引用‖和―弱引用‖比较少见。

他们一般被作为缓存使用,而且一般是在内存大小比较受限的情况下做为缓存。

因为如果内存足够大的话,可以直接使用强引用作为缓存即可,同时可控性更高。

因而,他们常见的是被使用在桌面应用系统的缓存。

JVM调优总结(三)-基本垃圾回收算法可以从不同的的角度去划分垃圾回收算法:按照基本回收策略分引用计数(Reference Counting):比较古老的回收算法。

原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。

垃圾回收时,只用收集计数为0的对象。

此算法最致命的是无法处理循环引用的问题。

标记-清除(Mark-Sweep):此算法执行分两阶段。

第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。

此算法需要暂停整个应用,同时,会产生内存碎片。

复制(Copying):此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。

垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。

次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现―碎片‖问题。

当然,此算法的缺点也是很明显的,就是需要两倍内存空间。

标记-整理(Mark-Compact):此算法结合了―标记-清除‖和―复制‖两个算法的优点。

也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象―压缩‖到堆的其中一块,按顺序排放。

此算法避免了―标记-清除‖的碎片问题,同时也避免了―复制‖算法的空间问题。

按分区对待的方式分增量收集(Incremental Collecting):实时垃圾回收算法,即:在应用进行的同时进行垃圾回收。

不知道什么原因JDK5.0中的收集器没有使用这种算法的。

分代收集(Generational Collecting):基于对对象生命周期分析后得出的垃圾回收算法。

把对象分为年青代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。

现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。

按系统线程分串行收集:串行收集使用单线程处理所有垃圾回收工作,因为无需多线程交互,实现容易,而且效率比较高。

但是,其局限性也比较明显,即无法使用多处理器的优势,所以此收集适合单处理器机器。

当然,此收集器也可以用在小数据量(100M左右)情况下的多处理器机器上。

并行收集:并行收集使用多线程处理垃圾回收工作,因而速度快,效率高。

而且理论上CPU 数目越多,越能体现出并行收集器的优势。

并发收集:相对于串行收集和并行收集而言,前面两个在进行垃圾回收工作时,需要暂停整个运行环境,而只有垃圾回收程序在运行,因此,系统在垃圾回收时会有明显的暂停,而且暂停时间会因为堆越大而越长。

相关文档
最新文档