`
comeonbabye
  • 浏览: 438417 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JVM内存的调优

阅读更多

.JVM 内存 的设置的原理

默认的 java 虚拟机的大小比较小,在对大数据进行处理时 java 就会报错: java.lang.OutOfMemoryError 。设置 jvm 内存 的方法,对于单独的 .class ,可以用下面的方法对 Test 运行时的 jvm 内存 进行设置。
java -Xms64m -Xmx256m Test
-Xms
是设置内存 初始化的大小
-Xmx
是设置最大能够使用内存 的大小(最好不要超过物理内存 大小)
weblogic 中,可以在 startweblogic.cmd 中对每个 domain 虚拟内存 的大小进行设置,默认的设置是在 commEnv.cmd 里面。

-vmargs
-Xms128M
-Xmx512M
-XX:PermSize=64M
-XX:MaxPermSize=128M

下面是这几个设置的一些背景知识:

  • 堆(Heap)和非堆(Non-heap)内存
    按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存 均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM 中堆之外的内存 称为非堆内存 (Non-heap memory)”。可以看出JVM 主要管理两种类型的内存 :堆和非堆。简单来说堆就是Java代码可及的内存 ,是留给开发人员使用的;非堆就是JVM 留给 自己用的,所以方法区、JVM 内部处理或优化所需的内存 (如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存 中。
  • 内存 分配
    JVM 初始分配的内存 由-Xms指定,默认是物理内存 的1/64;JVM 最 大分配的内存 由-Xmx指定,默认是物理内存 的1/4。默认空余堆内存 小于40%时,JVM 就会增大堆直到-Xmx的最大限制;空余堆内存 大于70%时, JVM 会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。
  • 非堆内存 分配
    JVM 使用-XX:PermSize设置非堆内存 初始值,默认是物理内存 的1/64;由XX:MaxPermSize设置最大非堆内存 的大小,默认是物理内存 的1/4。
  • JVM 内存 限制(最大值)
    首先JVM 内存 首先受限于实际的最大物理内存 ,假设物理内存 无限 大的话,JVM 内存 的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存 空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是 2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了
  • JVM 内存 的调优

    1. Heap 设定与垃圾回收 Java Heap 分为 3 个区, Young Old Permanent Young 保存刚实例化的对象。当该区被填满时, GC 会将对象移到 Old 区。 Permanent 区则负责保存反射对象,本文不讨论该区。 JVM Heap 分配可以使用 -X 参数设定,

    -Xms

    初始 Heap 大小

    -Xmx

    java heap 最大值

    -Xmn

    young generation heap 大小

    JVM 2 GC 线程。第一个线程负责回收 Heap Young 区。第二个线程在 Heap 不足时,遍历 Heap ,将 Young 区升级为 Older 区。 Older 区的大小等于 -Xmx 减去 -Xmn ,不能将 -Xms 的值设的过大,因为第二个线程被迫运行会降低 JVM 的性能。

    为什么一些程序频繁发生 GC ?有如下原因:

    l         程序内调用了 System.gc() Runtime.gc()

    l         一些中间件软件调用自己的 GC 方法,此时需要设置参数禁止这些 GC

    l         Java Heap 太小,一般默认的 Heap 值都很小。

    l         频繁实例化对象, Release 对象。此时尽量保存并重用对象,例如使用 StringBuffer() String()

             如果你发现每次 GC 后, Heap 的剩余空间会是总空间的 50% ,这表示你的 Heap 处于健康状态。许多 Server 端的 Java 程序每次 GC 后最好能有 65% 的剩余空间。经验之谈:

    1 Server JVM 最好将 -Xms -Xmx 设为相同值。为了优化 GC ,最好让 -Xmn 值约等于 -Xmx 1/3[2]

    2 .一个 GUI 程序最好是每 10 20 秒间运行一次 GC ,每次在半秒之内完成 [2]

    注意:

    1 .增加 Heap 的大小虽然会降低 GC 的频率,但也增加了每次 GC 的时间。并且 GC 运行时,所有的用户线程将暂停,也就是 GC 期间, Java 应用程序不做任何工作。

    2 Heap 大小并不决定进程的内存 使用量。进程的内存 使用量要大于 -Xmx 定义的值,因为 Java 为其他任务分配内存 ,例如每个线程的 Stack 等。

    2 Stack 的设定

    每个线程都有他自己的 Stack

    -Xss

    每个线程的 Stack 大小

    Stack 的大小限制着线程的数量。如果 Stack 过大就好导致内存 溢漏。 -Xss 参数决定 Stack 大小,例如 -Xss1024K 。如果 Stack 太小,也会导致 Stack 溢漏。

    3 .硬件环境

    硬件环境也影响 GC 的效率,例如机器的种类,内存 swap 空间,和 CPU 的数量。

    如果你的程序需要频繁创建很多 transient 对象,会导致 JVM 频繁 GC 。这种情况你可以增加机器的内存 ,来减少 Swap 空间的使用 [2]

    4 4 GC

    第一种为单线程 GC ,也是默认的 GC 。,该 GC 适用于单 CPU 机器。

    第二种为 Throughput GC ,是多线程的 GC ,适用于多 CPU ,使用大量线程的程序。第二种 GC 与第一种 GC 相似,不同在于 GC 在收集 Young 区是多线程的,但在 Old 区和第一种一样,仍然采用单线程。 -XX:+UseParallelGC 参数启动该 GC

    第三种为 Concurrent Low Pause GC ,类似于第一种,适用于多 CPU ,并要求缩短因 GC 造成程序停滞的时间。这种 GC 可以在 Old 区的回收同时,运行应用程序。 -XX:+UseConcMarkSweepGC 参数启动该 GC

    第四种为 Incremental Low Pause GC ,适用于要求缩短因 GC 造成程序停滞的时间。这种 GC 可以在 Young 区回收的同时,回收一部分 Old 区对象。 -Xincgc 参数启动该 GC

    4 GC 的具体描述参见 [3]

     

    参考文章:

    1. JVM Tuning. http://www.caucho.com/resin-3.0/performance/jvm -tuning.xtp#garbage-collection

    2. Performance tuning Java: Tuning steps

    http://h21007.www2.hp.com/dspp/tech/tech_TechDocumentDetailPage_IDX/1,1701,1604,00.html

    3. Tuning Garbage Collection with the 1.4.2 JavaTM Virtual Machine .

    http://java.sun.com/docs/hotspot/gc1.4.2/

     

    二. Tomcat 配置

    问题分析:

       由于 TOMCAT 内存 溢出而引发的问题,主要原因是 JVM 的虚拟内存 默认为 128M ,当超过这个值时就把先前占用的内存 释放,而导致好象 TCP/IP 丢包的假象,出现 HTTP500 的错误。解决方法主要是加大 TOMCAT 可利用内存 ,并在程序当中加大内存 使用。

     

    解决方法:

    方法:加大 TOMCAT 可利用内存

      在 TOMCAT 的目录下,也就是在 TOMCAT41/bin/catalina.bat 文件最前面加入

       set JAVA_OPTS=-Xms800m -Xmx800m

      表现效果是当你启动 TOMCAT 时,系统内存 会增加近 800M 使用

    操作方法:

       1 )、先关掉 WINDOWS 服务当中的 TOMCAT4 服务。

       2 )、再找到 TOMCAT/BIN 目录下 startup.bat ,双击打开它,你会发现现 WINDOWS 内存 占用会增加近 800M

       3 )、执行程序,因为是 TOMCAT 重新编译程序,所以第一次会比较慢。

    结论:

    经过测试,我们得出如下数据:

    当系统传输约 2000 条数据时,大约近 12M 的净数据(不压缩时),系统辅助运行的内存 大约占用 150M 左右的空间,也就是近 200M 内存 占用,而我们扩大了近 800M JAVA 内存 使用,这对于业务本身来说是足够了。所以你们不用担心大数据量的传递问题。

    基于 JAVA 虚拟机的原理, JAVA 自动有垃圾回收机制,也就是在你对一些内存 长时间不使用时(近 2 分钟,取决于使用频度和优先级等),就会自动垃圾回收,从而释放不用的内存 占用。

     

    .WebLogic 配置:

      由于 WebLogic 的配置问题,我们的测试出现了失败情况。原因是为 WebLogic 分配的内存 太少了。通过修改 commom/bin/commEnv.cmd 文件来增加内存 分配。

      修改的部分如下:

    :bea

    if "%PRODUCTION_MODE%" == "true" goto bea_prod_mode

    set JAVA_VM=-jrockit

    set MEM_ARGS=-Xms768m -Xmx1024m

    set JAVA_OPTIONS=%JAVA_OPTIONS% -Xverify:none

    goto continue

    :bea_prod_mode

    set JAVA_VM=-jrockit

    set MEM_ARGS=-Xms768m -Xmx1024m// 原来是 128M ~256M ,太小了,数据太大

    goto continue

      结果修改后,没有效果。还是有失败的情况。

      发现,原来,在: bea 下面还有一段配置信息如下:

    :sun

    if "%PRODUCTION_MODE%" == "true" goto sun_prod_mode

    set JAVA_VM=-client

    set MEM_ARGS=-Xms768m -Xmx1024m -XX:MaxPermSize=256m

    set JAVA_OPTIONS=%JAVA_OPTIONS% -Xverify:none

    goto continue

    :sun_prod_mode

    set JAVA_VM=-server

    set MEM_ARGS=-Xms768m -Xmx1024m -XX:MaxPermSize=256m

    goto continue

      将这里的内存 分配修改后见效。

      原因是,上面对第一段代码是为 bea 自己的 JVM 设置的,下面的是为 Sun 的设置的。而 WebLogic 默认的是 Sun 的,所以出了毛病。在 JDK 的选择上, weblogic 有两种 JDK 供选择,一种是 Sun JDK ,另外一种是 Bea jrockit 。按照 bea 的网站的说明, sun jdk 提供更好的兼容性,而使用 jrockit 可以提供更好的性能。作为 weblogic 集群我全部采用 jrockit 作为 JDK 环境,以达到更高的性能。

     

    在默认启动情况下, jrockit 启动时为其窗口配置的内存 大小比较小。注意 weblogic 的启动内存 配置 -Xms32m -Xmx256m ,通过修改 commEnv.sh 可以修改这个参数, Xms 表示启动开始分配的内存 Xmx 表示最大能分配的内存 ,这里我们根据应用情况调整为 -Xms1536m -Xmx1536m ,这点需要根据自身测试情况和系统配置进行调整,经过周一晚的调试,我们目前应用比较合理的窗口内存 大小为 1536M 2G × 75 %),通过 top 可以观察到测试中的内存 反应,最合理的应该是恰好把物理内存 用完。

    分享到:
    评论

    相关推荐

    Global site tag (gtag.js) - Google Analytics