cat /proc/[pid]/status
经过/proc/[pid]/status能够查看进程的内存使用状况,包括虚拟内存大小(VmSize),物理内存大小(VmRSS),数据段大小(VmData),栈的大小(VmStk),代码段的大小(VmExe),共享库的代码段大小(VmLib)等等。java
* Name: java /*进程的程序名*/ * State: S (sleeping) /*进程的状态信息,具体参见*/ * Tgid: 9744 /*线程组号*/ * Pid: 9744 /*进程pid*/ * PPid: 7672 /*父进程的pid*/ * TracerPid: 0 /*跟踪进程的pid*/ * VmPeak: 60184 kB /*进程地址空间的大小*/ * VmSize: 60180 kB /*进程虚拟地址空间的大小reserved_vm:进程在预留或特殊的内存间的物理页*/ * VmLck: 0 kB /*进程已经锁住的物理内存的大小.锁住的物理内存不能交换到硬盘*/ * VmHWM: 18020 kB /*文件内存映射和匿名内存映射的大小*/ * VmRSS: 18020 kB /*应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)*/ * VmData: 12240 kB /*程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据*/ * VmStk: 84 kB /*进程在用户态的栈的大小*/ * VmExe: 576 kB /*程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 */ * VmLib: 21072 kB /*被映像到任务的虚拟内存空间的库的大小*/ * VmPTE: 56 kB /*该进程的全部页表的大小*/ * Threads: 1 /*共享使用该信号描述符的任务的个数*/
java内存组成介绍:堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具备一个堆,堆是运行时数据区域,全部类实例和数组的内存均今后处分配。堆是在 Java 虚拟机启动时建立的。” “在JVM中堆以外的内存称为非堆内存(Non-heap memory)”。nginx
能够看出JVM主要管理两种类型的内存:堆和非堆。算法
简单来讲堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给本身用的。数组
因此方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每一个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。浏览器
JVM 自己须要的内存,包括其加载的第三方库以及这些库分配的内存缓存
NIO 的 DirectBuffer 是分配的 native memory服务器
内存映射文件,包括 JVM 加载的一些 JAR 和第三方库,以及程序内部用到的。上面 pmap 输出的内容里,有一些静态文件所占用的大小不在 Java 的 heap 里,所以做为一个Web服务器,赶忙把静态文件从这个Web服务器中人移开吧,放到nginx或者CDN里去吧。app
JIT, JVM会将Class编译成native代码,这些内存也不会少,若是使用了Spring的AOP,CGLIB会生成更多的类,JIT的内存开销也会随之变大,并且Class自己JVM的GC会将其放到Perm Generation里去,很难被回收掉,面对这种状况,应该让JVM使用ConcurrentMarkSweep GC,并启用这个GC的相关参数容许将不使用的class从Perm Generation中移除, 参数配置:-XX:+UseConcMarkSweepGC -X:+CMSPermGenSweepingEnabled -X:+CMSClassUnloadingEnabled,若是不须要移除而Perm Generation空间不够,能够加大一点:-X:PermSize=256M -X:MaxPermSize=512Mjvm
JNI,一些JNI接口调用的native库也会分配一些内存,若是遇到JNI库的内存泄露,可使用valgrind等内存泄露工具来检测ide
线程栈,每一个线程都会有本身的栈空间,若是线程一多,这个的开销就很明显了
也称”永久代” 、“非堆”,它用于存储虚拟机加载的类信息、常量、静态变量、是各个线程共享的内存区域。默认最小值为 16 MB,最大值为 64 MB,能够经过-XX: PermSize 和 -XX: MaxPermSize 参数限制方法区的大小。
运行时常量池:是方法区的一部分,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译器生成的各类符号引用,这部份内容将在类加载后放到方法区的运行时常量池中。
描述的是java 方法执行的内存模型:每一个方法被执行的时候 都会建立一个“栈帧”用于存储局部变量表(包括参数)、操做栈、方法出口等信息。
每一个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。声明周期与线程相同,是线程私有的。
局部变量表存放了编译器可知的各类基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并不是对象自己),其中64位长度的long和double类型的数据会占用2个局部变量的空间,其他数据类型只占1个。
局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法须要在栈帧中分配多大的局部变量是彻底肯定的,在运行期间栈帧不会改变局部变量表的大小空间。
与虚拟机栈基本相似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。
也叫作java 堆、GC堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时建立。
该内存区域存放了对象实例及数组(全部 new 的对象)。其大小经过 -Xms (最小值) 和 -Xmx (最大值) 参数设置,-Xms为 JVM 启动时申请的最小内存,默认为操做系统物理内存的 1/64 但小于 1G;
-Xmx 为 JVM 可申请的最大内存,默认为物理内存的1/4但小于 1G,默认当空余堆内存小于 40% 时,JVM 会增大 Heap 到 -Xmx 指定的大小,可经过 -XX:MinHeapFreeRation= 来指定这个比列;
当空余堆内存大于70%时,JVM 会减少 heap 的大小到 -Xms 指定的大小,可经过XX:MaxHeapFreeRation= 来指定这个比列,对于运行系统,为避免在运行时频繁调整 Heap 的大小,一般 -Xms 与 -Xmx 的值设成同样。
因为如今收集器都是采用分代收集算法,堆被划分为新生代和老年代。新生代主要存储新建立的对象和还没有进入老年代的对象。老年代存储通过屡次新生代GC(Minor GC)任然存活的对象。
是最小的一块内存区域,它的做用是当前线程所执行的字节码的行号指示器,在虚拟机的模型里,字节码解释器工做时就是经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都须要依赖计数器完成。
直接内存并非虚拟机内存的一部分,也不是Java虚拟机规范中定义的内存区域。jdk1.4中新加入的NIO,引入了通道与缓冲区的IO方式,它能够调用Native方法直接分配堆外内存,这个堆外内存就是本机内存,不会影响到堆内存的大小。
[root@server ~]$ jmap -heap 837 Attaching to process ID 837, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.71-b01 using thread-local object allocation. Parallel GC with 4 thread(s)//GC 方式 Heap Configuration: //堆内存初始化配置 MinHeapFreeRatio = 0 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40) MaxHeapFreeRatio = 100 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70) MaxHeapSize = 2082471936 (1986.0MB) //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小 NewSize = 1310720 (1.25MB)//对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小 MaxNewSize = 17592186044415 MB//对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小 OldSize = 5439488 (5.1875MB)//对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小 NewRatio = 2 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率 SurvivorRatio = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值 PermSize = 21757952 (20.75MB) //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小 MaxPermSize = 85983232 (82.0MB)//对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小 G1HeapRegionSize = 0 (0.0MB) Heap Usage://堆内存使用状况 PS Young Generation Eden Space://Eden区内存分布 capacity = 33030144 (31.5MB)//Eden区总容量 used = 1524040 (1.4534378051757812MB) //Eden区已使用 free = 31506104 (30.04656219482422MB) //Eden区剩余容量 4.614088270399305% used //Eden区使用比率 From Space: //其中一个Survivor区的内存分布 capacity = 5242880 (5.0MB) used = 0 (0.0MB) free = 5242880 (5.0MB) 0.0% used To Space: //另外一个Survivor区的内存分布 capacity = 5242880 (5.0MB) used = 0 (0.0MB) free = 5242880 (5.0MB) 0.0% used PS Old Generation //当前的Old区内存分布 capacity = 86507520 (82.5MB) used = 0 (0.0MB) free = 86507520 (82.5MB) 0.0% used PS Perm Generation//当前的 “永生代” 内存分布 capacity = 22020096 (21.0MB) used = 2496528 (2.3808746337890625MB) free = 19523568 (18.619125366210938MB) 11.337498256138392% used 670 interned Strings occupying 43720 bytes.
前面jmap输出的内容里,MaxHeapSize 是在命令行上配的,-Xmx4096m,这个java程序能够用到的最大堆内存。
VSZ是指已分配的线性空间大小,这个大小一般并不等于程序实际用到的内存大小,产生这个的可能性不少,好比内存映射,共享的动态库,或者向系统申请了更多的堆,都会扩展线性空间大小,要查看一个进程有哪些内存映射,可使用 pmap 命令来查看:
pmap -x [pid]
[root@server ~]$ pmap -x 837 837: java Address Kbytes RSS Dirty Mode Mapping 0000000040000000 36 4 0 r-x-- java 0000000040108000 8 8 8 rwx-- java 00000000418c9000 13676 13676 13676 rwx-- [ anon ] 00000006fae00000 83968 83968 83968 rwx-- [ anon ] 0000000700000000 527168 451636 451636 rwx-- [ anon ] 00000007202d0000 127040 0 0 ----- [ anon ] ... ... 00007f55ee124000 4 4 0 r-xs- az.png 00007fff017ff000 4 4 0 r-x-- [ anon ] ffffffffff600000 4 0 0 r-x-- [ anon ] ---------------- ------ ------ ------ total kB 7796020 3037264 3023928
这里能够看到不少anon,这些表示这块内存是由mmap分配的。
RSZ是Resident Set Size,常驻内存大小,即进程实际占用的物理内存大小, 在如今这个例子当中,RSZ和实际堆内存占用差了2.3G,这2.3G的内存组成分别为:
jstat -gcutil [pid]
[root@server ~]$ jstat -gcutil 837 1000 20 S0 S1 E O P YGC YGCT FGC FGCT GCT 0.00 80.43 24.62 87.44 98.29 7101 119.652 40 19.719 139.371 0.00 80.43 33.14 87.44 98.29 7101 119.652 40 19.719 139.371
分析 JVM 堆内存中的对象
jmap -histo:live [pid]
jmap -dump:format=b,file=heapDump [pid]
jhat -port 5000 heapDump
在浏览器中访问:http://localhost:5000/ 查看详细信息