(转)一步步优化JVM4:决定Java堆的大小以及内存占用
一步步优化JVM4:决定Java堆的大小以及内存占用
http://www.myexception.cn/program/564386.html
一步步优化JVM四:决定Java堆的大小以及内存占用
? ?到目前为止,还没有做明确的优化工作。只是做了初始化选择工作,比如说:JVM部署模型、JVM运行环境、收集哪些垃圾回收器的信息以及需要遵守垃圾回收原则。这一步将介绍如何评估应用需要的内存大小以及Java堆大小。首先需要判断出应用存活的数据的大小,存活数据的大小是决定配置应用需要的Java堆大小的重要条件,也能够决定是否需要重新审视一下应用的内存需求或者修改应用程序以满足内存需求。
约束? ?有多少物理内存可以供JVM使用?是部署多个JVM或者单个JVM?对做出的决定有重要影响。下面列出了一些要点可以帮助决定有多少物理内存可以供使用。? ?1、一个机器上面只是部署一个JVM,且就一个应用使用?如果是这种情况,那么机器的所有物理内存可以供JVM使用。? ?2、一个机器上部署了多个JVM?或者一个机器上部署了多个应用?如果是这两个中的任何一种情况,你就必须要决定每一个JVM或者应用需要分配多少内存了。? ?无论是前面的哪种情况,都需要给操作系统留出一些内存。HotSpot VM的堆结构? ?在做内存占用测量之前,我们必须要先理解HotSpot VM Java堆的结构,理解这个对决定应用需要的Java堆大小以及优化垃圾收器性能有很好的帮助。

? ?HotSpot VM有3个主要的空间:young代、old代以及permanent代,如上图所示。? ?当Java应用分配Java对象时,这些对象被分配到young代。在经历过几次minor GC之后,如果对象还是存活的,就会被转移到old代空间。permanent代空间存储了VM和Java类的元数据比如内置的字符串和类的静态变量。
? ?-Xmx和-Xms这个两个命令行选项分别指定yound代加上old代空间的总和的初始最大值和最小值,也就是Java堆的大小。当-Xms的值小于-Xmx的值的时候,Java堆的大小可以在最大值和最小值之前浮动。当Java应用强调吞吐量和延迟的时候,倾向于把-Xms和-Xmx设置成相同的值,由于调整young代或者old代的大小都需要进行Full GC,Full GC降低吞吐量以及加强延迟。
? ?young代的空间可以通过下面的任意一个命令行选项来设置:
? ?上面重要的部分加粗标示了,由于使用的是吞吐量垃圾回收器,old代的统计信息标示为ParOldGen。这行表示了old代的在FullGC的时候占用的空间。从这个结果来看,可以得出的结论是old代的空间太小了,由于FullGC前后old代的被占用的空间和分配的空间基本相等了,因此,JVM报了OutOfMemoryError。相比较,通过PSPermGen这行可以看出permanent代的空间占用是32390K,和他的容量(65536K)比还是有一定的距离。下面的例子展示了由于permanent太少了而导致的OutOfMemoryError发生的例子? ?通过活动对象大小的信息,可以做出关于Java堆的大小有根据的决定,以及可以估计出最坏情况下会导致的延迟。
? ?比较常规是,Java堆大小的初始化值和最大值(通过-Xms和-Xmx选项来指定)应该是old代活动对象的大小的3到4倍。
? ?在上图中显示的FullGC信息中,在FullGC之后old代的大小是295111K,差不多是295M,即活动的对象的大小是295M。因此,推荐的Java堆的初始化和最大值应该是885M到1180M,即可以设置为-Xms885m -Xmx1180m。在这个例子中,Java堆的大小是1048570K差不多1048M,在推荐值范围内。
? ?另外一个常规是,permanent的初始值和最大值(-XX:PermSize和-XX:MaxPermSize)应该permanent代活动对象大小的1.2到1.5倍。在上图中看到在FullGC之后permanent代占用空间是32390K,差不多32M。因此,permanent代的推荐大小是38M到48M,即可以设置为-XX:PermSize=48m -XX:MaxPermSize=48m(1.5倍)。这个例子里面,permanent代的空间大小是65536K即64M,大出了17M,不过在1G内存的系统的中,这个数值完全可以忍受。
? ?另外一个常规是,young代空间应该是old代活动对象大小的1到1.5倍。那么在这里例子中,young代的大小可以设置为295M到442M。本例里面,young代的空间大小的358400K,差不多358M,在推荐值中间。
? ?如果推荐的Java堆的初始值和最大值是活动对象大小3到4倍,而young代的推荐只是1到1.5倍,那么old代空间大小应该是2到3倍。
? ?通过以上规则,我们可以使用的Java命令可以是这样的:java -Xms1180m -Xmx1180m -Xmn295m -XX:PermSize=48m -XX:MaxPermSize=48m
另外一些考虑? ?本节将提及到在进行应用内存占用评估的时候,另外一些需要记住的点。首先,必须要知道,前面只是评估的Java堆的大小,而不是Java应用占用的所有的内存,如果要查看Java应用占用的所有内存在linux下可以通过top命令查看或者在window下面通过任务管理器来查看,尽管Java堆的大小可能对Java应用占用内存做出了最大的贡献。 比如说,为了存储线程堆栈,应用需要额外的内存,越多的线程,越多内存被线程栈消耗,越深的方法间调用,线程栈越多。另外,本地库需要分配额外的内存,I/O缓存也需要额外的内存。应用的内存消耗需要评估到应用任何一个会消耗内存的地方。
? ?记住,这一步操作不一定能够满足应用内存消耗的需求,如果不能满足,就回过头来看需求是否合理或者修改应用程序。比较可行的一种办法是修改应用程序减小对象的分配,从而减少内存的消耗。? ?Java堆的大小计算仅仅只是开始,根据需求,在后面的优化步骤中可能会修改。
? ?通过活动对象大小的信息,可以做出关于Java堆的大小有根据的决定,以及可以估计出最坏情况下会导致的延迟。