java jvm 内存优化_图解Java自动内存管理机制及JVM优化配置

Java与C++最重要的区别就是内存动态分配和垃圾收集技术。对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不需要为每一个new操作去写配对的delete/free,不容易出现内存泄漏和内存溢出错误,看起来由虚拟机管理内存这一切都很美好。但是也正是因为Java程序员把内存控制权交给了JVM,一旦出现内存泄漏或内存溢出,如果不了解JVM内存使用机制,那排查错误将会成为一件异常艰难的事情。下面为大家介绍JVM内存管理机制以及JVM的优化配置。

JVM运行时内存数据区域划分:

f9cc4b47f430766ab32abd37bde8f74b.png

各数据区域说明:

54ad30f1fb7b8db6bbf59e64350a4725.png

Java对象在内存中的访问

Object object = new Object();

Object object 存储在虚拟机栈的本地变量表中,作为一个引用reference类型数据存在。new Object() 存储在堆中,形成了一块存储了Object类型所有的实例数据的结构化内存。对象的访问实际就是通过reference访问到Java堆中的实例数据。reference访问对象有两种方式:

cb417c250d8f972478d4831f868d1b0c.png

垃圾回收(GC)

Java内存运行时区域中程序计数器、虚拟机栈、本地方法栈三个区域,生命周期与线程相同,随着线程的开始和结束而创建和销毁;而堆和方法区(包括运行时常量池)则不一样,必须等到程序运行期间才能知道会创建哪些对象,其内存的分配和回收都是动态进行的。对于这部分的对象,JVM是如何判断对象是可回收的呢?一般有两种方法,如下图:

aba7b8dac2be950f7e29f174c6625c3d.png

搜索算法是主流的方法,一般的面向对象语言都是使用此算法,比如Java、C#等;

判断对象是可回收的之后,是如何进行垃圾回收的呢?以下是各种垃圾收集算法介绍,如下图所示:

4f779d442748cc88bd4284b944af9b5e.png

Java中使用的垃圾收集算法是分代收集算法,其内存堆空间划分如下:

1b64f2efb677ad7354cff296d2f6e99c.png

从新生代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC(一般也成为Young GC)。对老年代进行的回收称为Major GC,但由于Major GC除并发GC外均需对整个堆空间—包括新生代和老年代清理,故又称为Full GC。由于Full GC时程序会暂停响应,如果JVM频繁的进行Full GC将使Java程序性能严重下降,说明此时JVM内存分配上肯定存在问题,需要进行JVM调优。

JDK1.6中提供的不同内存分代的收集器,两个收集器之间存在连线的话就说明可以搭配使用,如下图所示:

0269da18bf1379fc38c86727ebf59e95.png

垃圾收集器的特点、作用内存分代及如何使用的说明如下图:

0de5c940bb17442b0dab08675d196aab.png

上介绍了Java的自动内存管理机制,包括垃圾收集算法,收集器等,那么如何进行JVM调优呢?首先来看常用的JVM配置,如下图:

a94e70dd378ee8eb87fde2d421812ddd.png

小编常用的典型的JVM优化配置如下:

6435c5931b039f404adad0408569f798.png

-Xmx:设置JVM最大可用内存为4G;

-Xms:设置JVM初始内存为4G,一般设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存;

-Xmn1600M:设置新生代大小为1600M。整个JVM内存=新生代+老年代+持久代。持久代一般固定大小为64M,所以增大新生代后,将会减小老年代大小。此值对系统性能影响较大,官方推荐配置为整个堆的3/8;

-XX:PermSize=512M:设置持久代初始大小为512M。Java8中已经取消的了此参数,如配置了此参数,会产生告警ignoring option;

-XX:MaxPermSize=512M:设置持久代最大允许分配大小为512M。Java8中已经取消的了此参数,如配置了此参数,会产生告警ignoring option;

-XX:SurvivorRatio=20:设置新生代中Eden区与Survivor区的大小比值。设置为20,则两个Survivor区与一个Eden区的比值为2:20,一个Survivor区占整个新生代的1/22;

-XX:MaxTenuringThreshold=5:在新生代中对象存活次数(经过Minor GC的次数)后仍然存活,就会晋升到老年代。如果设置为0的话,则新生代对象不经过Survivor区,直接进入老年代。对于老年代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则新生代对象会在Survivor区进行多次复制,这样可以增加对象再新生代的存活时间,增加在新生代即被回收的概率;

-XX:+UseParNewGC:在新生代中使用为多线程(ParNew)收集器;

-XX:+UseConcMarkSweepGC:在老年代中使用并发收集CMS(ConcurrentMark Sweep)收集器;

-XX:CMSFullGCsBeforeCompaction=0:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生”碎片”,使得运行效率降低。此参数设置运行n次FullGC以后对内存空间进行压缩、整理;

-XX:+UseCMSCompactAtFullCollection:打开对老年代的压缩。可能会影响性能,但是可以消除内存碎片;

-XX:CMSInitiatingOccupancyFraction=85:表示老年代空间到85%时就开始执行CMS,确保老年代有足够的空间接纳来自新生代的对象;

-XX:SoftRefLRUPolicyMSPerMB=0:”软引用”的对象在最后一次被访问后能存活0毫秒(默认为1秒);

-XX:+CMSClassUnloadingEnabled:相对于并行收集器,CMS收集器默认不会对持久代进行垃圾回收。如果希望对持久代进行垃圾回收,需要设置此参数;

-XX:-CMSParallelRemarkEnabled:手动配置开启并行标记,节省新生代标记时间,JDK1.6以前不需要配置,默认开启;

-XX:-ReduceInitialCardMarks:取消Card-Marking优化。

以上典型配置下Java内存情况,使用jmap -heap *(*表示实际的Java应用进程号)可以查看内存使用情况,如下示例:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值