5.性能优化-监控-硬件资源监控-内存

1.概述
系统在进行页面交换或使用虚拟内存时,Java应用就会出现明显的性能问题。当应用运行所需的内存超过可用物理内存时,就会发生页面交换。当应用耗尽物理内存时,操作系统将应用的一部分交换到swap区,当应用再次访问这些内存时,再将这部分内容交换到内存中,这种页面交换会对应用的性能造成很大影响。
Java应用一般将-Xms和-Xmx避免运行期频繁的进行垃圾收集和内存的扩充。
2.free命令
# free
total used free shared buffers cached
Mem: 1309844 1040184 269660 0 38104 283832
-/+ buffers/cache: 718248 591596
Swap: 4161528 2408 4159120

第1行:
total --内存总量
used1 --使用内存数
free1 --空闲内存数
shared --共享内存数
buffers --块设备缓存大小
cached --文件缓存大小
第二行:
used2 --减去buffers/cached的内存数 = used1-buffers -cached
free2 --加上buffers/cached的内存数 =free1+buffers+cached
第三行:
total --总虚拟内存量
used --使用虚拟内存量
free --空闲虚拟内存量
3.vmstat命令
#vmstat 3
procs ----------[color=red][b]-memory---------- --------------swap-- ---[/b][/color]------------io---- --------system-- -----cpu-----
r b [color=red][b] swpd free buff cache si so [/b][/color] bi bo in cs us sy id wa st
0 0 90340 26756 20396 214080 503 1 0 100 90 206 0 1 95 3 0
0 0 90340 26756 20396 214084 0 0 0 0 58 144 0 0 100 0 0
0 0 90340 26632 20404 214084 48 0 0 0 85 185 0 0 100 0 0
0 0 90340 26632 20404 214084 0 0 0 0 63 145 0 0 100 0 0
0 0 90340 26632 20404 214084 43 0 0 0 80 176 0 0 100 0 0
0 0 90340 26632 20404 214084 0 0 0 0 69 155 0 0 100 0 0
0 0 90340 26632 20412 214084 16 0 0 0 76 174 0 1 99 0 0
0 0 90340 26632 20412 214084 0 0 0 0 76 160 0 0 100 0 0

memory:
swpd --虚拟内存使用情况 ,单位kb
free --空闲内存,单位kb
buffer --块设备缓存大小,单位kb
cache --文件缓存大小,单位kb
swap:
si --从磁盘交换到内存的页数量 ,单位kb/s
so --从内存交换到磁盘的页数量,单位kb/s

其他参数解释,见CPU篇。

加红加粗内容为内存有关的资源使用情况。
4.pidstat命令
#pidstat -p <pid> -r 1 3
Linux 2.6.32-71.el6.i686 (centos) 06/20/2014 _i686_ (1 CPU)

09:16:33 PM PID minflt/s majflt/s VSZ RSS %MEM Command
09:16:34 PM 7773 0.00 0.00 1453384 25088 1.92 java
09:16:35 PM 7773 0.00 0.00 1453384 25088 1.92 java
09:16:36 PM 7773 0.00 0.00 1453384 25088 1.92 java
Average: 7773 0.00 0.00 1453384 25088 1.92 java

PID --进程Id
minflt/s : 进程minor faults(不需要从磁盘中调出内存页)的总数
majflt/s : 进程major faults(需要从磁盘中调出内存页)的总数
VSZ: 进程使用的虚拟内存总数,单位KB
RSS:进程使用的物理内存总数,单位KB
%MEM:内存占用百分比
Command :命令

5.内存资源瓶颈
swpd过高,通常由于物理内存不够用了,系统会将内存中的一部分内容放入到硬盘中(so),当运行程序变化后,将从硬盘中重新读入到内存中(si),由于IO速度慢,此过程会严重影响系统的性能。此时free会很低,并伴有大量的si和so。

如果buffer和cached很高则说明缓存的命中率低。

一般情况下,JVM内存使用率大于80%,就需要进行JVM优化了。

Full GC频率应该平均小于半小时一次。

6.内存占用代码示例
java内存占用=堆占用+方法区占用+Direct ByteBuffer+线程消耗
设置了-Xms,java启动后只是占据了-Xms的地址空间,并没有占用实际的内存,只有相应的地址空间被使用过以后才会被计入消耗的内存中。
代码:
import java.nio.ByteBuffer;

public class DirectByteBufferDemo {
public static void main(String[] args) throws Exception{
Thread.sleep(20000);
System.out.println("ready to create bytes,so JVM heap will be used");
byte[] bytes = new byte[128*1000*1000];
bytes[0]=1;
bytes[1]=2;
Thread.sleep(10000);
System.out.println("ready to allocate & put direct bytebuffer,no JVM heap should be used");
ByteBuffer buffer = ByteBuffer.allocateDirect(128*1024*1024);
buffer.put(bytes);
buffer.flip();
Thread.sleep(10000);
System.out.println("ready to gc,JVM heap will be freed");
bytes = null;
System.gc();
Thread.sleep(10000);
System.out.println("ready to get bytes,then JVM heap will be used");
byte[] resultbytes = new byte[128*1000*1000];
buffer.get(resultbytes);
System.out.println("resultbytes[1] is:"+resultbytes[1]);
Thread.sleep(10000);
System.out.println("ready to gc all");
buffer = null;
resultbytes = null;
System.gc();
Thread.sleep(10000);
}
}

加上jvm运行参数 -Xms140m -Xmx140m运行。
运行结果:
Java进程内存 JVM堆内存
ready to create bytes 上涨 98%左右
read to allocate & put direct bytebuffer 翻倍 无变化
ready to gc 无变化 0.1%左右
ready to get bytes 无变化 98%左右
ready to gc all 回到最初大小 0.1%左右


结果说明:
1)direct bytebuffer消耗的是堆外的内存。
2)一旦堆使用后,gc也不会减少其内存消耗。
3)direct bytebuffer同样基于gc方式释放。

7.ThreadLocal
代码:
public class ThreadLocalDemo {
public static void main(String[] args) throws Exception{
ThreadLocalDemo demo = new ThreadLocalDemo();
demo.run();
}
public void run(){
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(new Task());
System.gc();
}
class Task implements Runnable{
public void run(){
ThreadLocal<byte[]> localString = new ThreadLocal<byte[]>();
localString.set(new byte[1024*1024*30]);
}
}
}


结果:
一直有30m的内存占用。

结果说明:
ThreadLocal中存放的对象,如果未做主动的释放,则不会被GC,需要线程执行完毕后,通过ThreadLocal.set把对象清除。


8.参考资料
《Java性能优化权威指南》
葛一鸣:《Java性能优化》
林昊:《分布式Java应用:基础与实践》
《淘宝性能测试白皮书2012最新版本》
http://www.cnblogs.com/net2012/archive/2013/01/18/2866907.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值