《Java性能优化...》读书笔记

时间:2023-01-03 21:35:11

1、JVM虚拟机内存分配参数

-Xmx:设置最大堆大小,最大堆指的是新生代和年老代的大小之和的最大值,它是Java应用程序的堆上限。当使用值超过这个限制时会抛出OutOfMemoryError异常。

可以使用循环申请1M空间(new byte[1024*1024])进行测试,

-Xms:设置最小堆(可以认为后面的s代表small)大小,Java应用程序在运行时,首先会被分配-Xms指定的内存大小,并尽可能尝试在这个空间段内运行程序。当-Xms指定的内存大小无法满足应用程序时,JVM才会向操作系统申请更多的内存,知道到-Xmx。

-Xmn:设置新生代(可以认为后面的n代表new)大小,设置一个较大的新生代会减小年老代的大小,这个参数对系统性能以及GC行为有很大的影响。新生代的大小一般设置为整个堆空间的1/4到1/3左右。设置新生代还可以使用参数-XX:NewSize和-XX:MaxNewSize。

-XX:MaxPermSize,-XX:PermSize:设置持久代(方法区)的大小,持久代不属于堆的一部分。前者是设置持久代的最大值,后者是设置初始大小。持久代的大小直接决定了系统可以支持多少个类和多少常量。对于使用CGLIB或者Javassist等动态字节码生成工具的应用程序而言,设置合理的持久代大小有助于维持系统稳定。

-Xss:设置线程栈,线程栈是线程的一块私有空间(注意在Java内存模型中,线程栈与堆空间是相互独立的两块区域)。在线程中进行局部变量分配,函数调用时,都需要在栈中开辟空间。如果栈的空间分配太小,那么线程在运行时,可能没有足够的空间分配局部变量或者达不到足够的函数调用深度,导致程序异常退出;如果栈空间过大,那么开设线程所需的内存成本就会上升,系统所能支持的线程总数就会下降。

 

2、堆的比例分配

         参数-XX:SurvivorRatio是用来设置新生代中,eden空间和s0空间的比例关系,s0和s1空间又分别称为from空间和to空间。它们的大小是相同的,只能也是一样的,并在Minor GC后,会互换角色。

         -XX:SurvivorRatio= eden/s0 = eden/s1

使用参数-XX:+PrintGCDetails –Xmx20M –XX:SurvivorRatio=2运行一段简单代码时,可以看到新生代中eden与from和to的比例,from空间和to空间是一样大的。

         参数-XX:NewRatio用来设置新生代和年老代的比例。

         -XX:NewRatio= 老年代/新生代

另外还有其他几个参数,-XX:PermSize设置永久区的初始值,--XX:MaxPermSize设置永久区的最大值。

 

3、几种垃圾收集算法:复制算法(Copying),复制算法的核心思想是,将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾收集。复制算法比较实时Java内存模型中的新生代的垃圾回收,因为新生代大部分对象都是朝生暮死的。

         标记整理算法(又叫标记压缩算法),这种算法在清理垃圾对象的同时,将还在使用的对象进行整理排放,因此没有碎片。这种算法适合老年代,因为老年代大部分对象都是存活的。

 

4、大对象直接进入老年代

         可以使用参数-XX:PretenureSizeThreshold设置大对象直接进入老年代的阈值。当对象的大小超过这个阈值的时候,将直接在老年代分配。-XX:PretenureSizeThreshold只对串行收集器和新生代并行收集器有效,并使回收收集器并不识别这个参数。因为尝试在新生代分配大对象,很可能导致空间不足,为了有足够的空间容纳对象,JVM不得不将新生代中的年轻对象(还活着的年轻的对象,死的直接垃圾回收了)挪到老年代。

设置对象进入老年代的年龄:

         如果对象在eden区,经过一次GC后还活着,则被移动到survivor区中,对象年龄加1,以后,对象每经过一次GC依然存活的,则年龄再加1。当对象年龄达到阈值时,就移入老年代,成为老年对象。这个阈值的最大值可以通过参数-XX:MaxTenuringThreshold来设置,它的默认值是15,但这并不意味着新对象非要达到这个年龄才能进入老年代。

 

5、实用JVM参数

         JVM的JIT(Just intime)编译器,可以在运行时将字节码编译成本地代码,从而提高函数的执行效率。-XX:CompileThreshold为JIT编译的阈值,当函数的调用次数超过这个阈值时,JIT就将字节码编译成本地机器码。在client模式下,-XX:CompileThreshold的取值是1500,在server模式下,取值是10000。JIT编译完成后,JVM便会用本地代码代替原来的字节码解释执行。

         对快照(堆Dump),在性能问题排查中,分析堆快照(Dump)是必不可少的一环。获得程序的对快照文件有多种方法。在本小节,介绍一种比较常见的获取对快照文件的方法,即使用-XX:+HeapDumpOnOutOfMemoryError参数在程序发生OOM时,导出应用程序的当前堆快照。这是一种非常有用的方法,因为在当程序发送OOM退出系统时,一些瞬间信息都随着程序的终止而消失,而重现OOM问题往往比较困难或者耗时。另外通过参数-XX:HeapDumpPath可以指定对快照的保存位置。导出的Dump文件可以通过Visual VM等多种工具查看分析,进而定位问题原因。后面会重点学习Visual VM的使用。

 

6、Java性能调优工具

         常见的Linux命令:

         sar命令也是linux系统中重要的性能检测工具之一,它可以周期性地对内存和CPU使用情况进行采样,基本语法如下:

         sar[ options ] [ <interval> ] [ <count> ]

其中interval和count分别表示采样周期和采样数量。options可以指定sar命令对哪些性能数据进行采样。-A:所有报告总和,-u:CPU利用率,-d:硬盘利用率,-b:I/O的情况,-r:内存,-n:网络。

         vmstat工具可以查看内存、交换分区、I/O操作,上下文切换、时钟中断以及CPU的使用情况,iostat可以提供详尽的I/O信息。

         JDK命令行工具:

         jstat命令是一个用于观察Java应用程序运行时信息的工具。它的功能非常强大,可以通过它查看堆信息的详细情况。比如使用jstat –gc线程号 (注意-gc一定要小写)命令可以查看堆内存的详细信息,比如堆中各个空间的大小,已经使用的空间等待。

       jmap命令可以生成Java应用程序的堆快照和对象的统计信息。堆快照信息生成之后还可以使用Visual VM工具进行分析。

         jstack命令用于导出Java应用程序的线程堆栈,这个命令可以查看线程是否死锁。

         jconsole工具

         jconsole工具是JDK自带的图形化性能监控工具。通过Jconsole工具,可以查看Java应用程序的运行概况,监控堆信息、永久区使用情况、类加载情况。jconsole一启动的时候,需要选择要连接的进程(运行一个main函数就是启动一个Java进程?)

         下面一个截图显示了如何使用jconsole来查看堆的信息,可以看到一般的内存使用量都能看到。

                                                       《Java性能优化...》读书笔记

另外,jconsole还可以查看线程数(包括峰值和活动线程,也可以查看所有的线程,以及各个线程的状态,比如TIMED_WAITING等,关于各个线程还有一个堆栈跟踪。),已经加载的类数量,CPU占用率等待,我擦还可以检测死锁,Jconsole控制台是不是就是所有jdk命令的一个综合啊?

         Visual VM工具

         visualVM也是JDK自带的工具(在bin目录里面,名字为jvisualvm)。这个工具是一个功能强大的多合一故障诊断和性能监控的可视化工具,它集成了很多性能统计工具,使用Visual VM可以替代jstat,jmap,jhat,jstack甚至jconsole。

         使用visual VM可以查看线程堆栈信息(ThreadDump)。

         VisualVM有两个采样器(Sampler)。在Sampler页面下,显示了CPU和内存两个性能采样器,用于实时地监控程序信息。CPU采样可以将CPU占用时间定位到方法(哪个方法消耗CPU时间最多)。内存采样器可以查看当前程序的堆信息(那个类占用的内存最多)

         通过选择右键菜单中的HeapDump命令,可以立即获得当前应用程序的内存快照。如下图所示,一共有四个基本功能项:概要(Summary), 类(Classes),实例数(Instances),和OQL控制台。

                                 《Java性能优化...》读书笔记

摘要页面的东西都在上图,不说了。在类页面,以类为索引,显示了每个类的实例所占用的空间。截图如下:

                                          《Java性能优化...》读书笔记

 

MAT内存分析工具

MAT是MemoryAnalyzer的简称,它是一款功能强大的Java堆内存分析器,可以用于查找内存泄露以及查看内存消耗情况。

         在分析堆快照前,首先需要导出应用程序的堆快照,jmap,jconsole,Visual VM等工具都可以用于获得Java应用程序的堆快照文件,此外MAT也有这个功能。

         以后有必要再慢慢学吧

 

 《Java性能优化,让你的Java程序更快更稳定》