tomcat 内存设置

一、Java 内存组成介绍

按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中.

  • 方法栈&本地方法栈:
    线程创建时产生,方法执行时生成栈帧

  • 方法区
    存储类的元数据信息 常量等


  • java代码中所有的new操作

  • native Memory(C heap)
    Direct Bytebuffer JNI Compile GC;

JVM内存限制(最大值)

首先 JVM 内存限制于最大物理内存,其次与操作系统有关。32位处理器下,windows 中为1.5G~2G,Linux 中为2G~3G,而64位处理器下没有限制。

JVM 内存设置的四个参数

-Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
-Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
-Xmn Java Heap Young区大小,不熟悉最好保留默认值;
-Xss 每个线程的Stack大小,不熟悉最好保留默认值;

堆内存分配

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。

测试

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
//JVM的最大可用内存,可通过-Xmx设置,默认值为物理内存的1/4,设值不能高于计算机物理内存
out.println("JVM MAX MEMORY: " + Runtime.getRuntime().maxMemory()/1024/1024+"M<br/>");
//当前JVM占用的内存总数,其值相当于当前JVM已使用的内存及freeMemory()的总和,会随着JVM使用内存的增加而增加;
out.println("JVM IS USING MEMORY:" + Runtime.getRuntime().totalMemory()/1024/1024+"M<br/>");
//当前JVM空闲内存,因为JVM只有在需要内存时才占用物理内存使用,所以freeMemory()的值一般情况下都很小,而JVM实际可用内存并不等于freeMemory(),而应该等于maxMemory()-totalMemory()+freeMemory()。及其设置JVM内存分配。
out.println("JVM IS FREE MEMORY:" + Runtime.getRuntime().freeMemory()/1024/1024+"M<br/>");
%>

修改前:

JVM MAX MEMORY: 3520M
JVM IS USING MEMORY:237M
JVM IS FREE MEMORY:203M

修改后:

JVM MAX MEMORY: 490M
JVM IS USING MEMORY:490M
JVM IS FREE MEMORY:461M

参考

tomcat 内存溢出问题

二、Linux 下的内存占用

修改了上面 tomcat 的 JVM 内存设置,发现内存占用的告警还是不断,于是找到了统计进程内存占用的告警脚本:

function GetMem()
{
        MEMUsage=`ps -o vsz -p $1|grep -v VSZ`
        ((MEMUsage /= 1024))
        echo $MEMUsage "MB"
}

按照这个命令统计出一个 tomcat 在共启动的时候就占了3G 的内存,明显说不过去。


从 ps 的结果来看,里面有两列 VSZ 和 RSS

  • VSZ: 占用的虚拟内存大小
  • RSS: 占用的物理内存的大小
  • %MEM: 占用的物理内存的使用率
  • STAT:
    STAT: 该行程的状态:
    D: 不可中断的静止
    R: 正在执行中
    S: 静止状态
    T: 暂停执行
    Z: 不存在但暂时无法消除
    W: 没有足够的记忆体分页可分配
    <: 高优先序的行程
    N: 低优先序的行程
    L: 有记忆体分页分配并锁在记忆体内
    D 不可中断 uninterruptible sleep (usually IO)
    R 运行 runnable (on run queue)
    S 中断 sleeping
    T 停止 traced or stopped
    Z 僵死 a defunct (”zombie”) process

  • START: 行程开始时间

  • TIME: 执行的时间

  • COMMAND:所执行的指令

[root@server000 ~]# ps aux|grep 36303
test     36303  0.5  2.6 3242768 433868 pts/0  Sl   14:00   0:27 /usr/java/jdk1.6.0_45/bin/java

RSS 才是我们关注的物理内存,也就是上面的433868/1024 = 423M。

参考:
ps 指令

2016-04-26 15:2934