利用 Runtime 监控 Java 系统资源

这些日子要用爪哇语言(Java)做内存数据中心。于是把用 Java 监控运行环境硬件资源的内容复习了一下。爪哇类库提供了 java.util.Runtim 类,主要负责调用爪哇虚拟机(JavaVM)外部的基层操作系统功能、处理基于一种叫钩子的原理的程序、获取系统资源信息以及控制调试信息生成。本文单独利用其获取系统资源信息的功能。

java.util.Runtim 类具有以下几个方法和获取系统资源信息有关。以下代码可不是简简单单从标准类库里边复制出来的哦。全球目前独此一份。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
 * 返回爪哇(Java)虚拟机可用线程数。
 *
 * <p>该值在特定的虚拟机调用期间可能发生更改。因此,对可用处理器数目很敏感的
 * 应用程序应该不定期地轮询该属性,并相应地调整其资源用法。</p>
 *
 * @return  虚拟机可用的最大处理器数目;从不小于 1
 * @since 1.4
 */
public native int availableProcessors();
/**
 * 返回爪哇(Java)虚拟机中的空闲内存量。调用 <code>gc</code> 方法可能导致
 * <code>freeMemory</code> 返回值的增加。
 *
 * @return  供将来分配对象使用的当前可用内存的近似总量,以字节为单位。
 */
public native long freeMemory();
/**
 * 返回爪哇(Java)虚拟机中的内存总量。此方法返回的值可能随时间的推移而变化,这
 * 取决于主机环境。
 * <p>
 * 注意,保存一个给定类型的对象所需的内存量可能取决于实现方式。
 *
 * @return  目前为当前和后续对象提供的内存总量,以字节为单位。
 */
public native long totalMemory();           //                                //
/**
 * 返回爪哇(Java)虚拟机能够尝试使用的最大内存量。如果内存本身没有限制,则
 * 返回值 {@link java.lang.Long#MAX_VALUE} 。 </p>
 *
 * @return  虚拟机能够尝试使用的最大内存量,以字节为单位。
 * @since 1.4
 */
public native long maxMemory();
/**
 * 运行垃圾回收器。
 * 调用此方法意味着爪哇(Java)虚拟机做了一些努力来回收未用对象,以便能够快速地
 * 重用这些对象当前占用的内存。当控制从方法调用中返回时,虚拟机已经尽最大努力回收
 * 了所有丢弃的对象。
 * <p>
 * 名称 <code>gc</code> 代表“垃圾回收器”。虚拟机根据需要在单独的线程中自动执行
 * 回收过程,甚至不用显式调用 <code>gc</code> 方法。
 * <p>
 * 方法 {@link System#gc()} 是调用此方法的一种传统而便捷的方式
 */
public native void gc();

我们可以看到这些都是本地方法。这意味着将 Runtime 对象远程传递之后,将不能得到正确执行结果。

这些方法用起来都很简单,文档注释也写得比较明白。
在高可用数据中心中,我认为应该根据可用 CPU 线数决定程序开启的线程数。此线程数为 CPU 可用线数的某倍数。此倍数应通过实际经验所得。然后程序通过监控 CPU 可用线数,来控制线程池保留数量。
内存的控制,我想应该是在内存超出警戒线时发出警报,以向运营人员申请增加内存数据中心服务器。同时,应该在内存过满之前,由程序执行垃圾回收,以消除并无引用的老生代对象。
如果各位有对内存数据中心的想法、建议或者质疑,欢迎来一起讨论。

下边是我编写的一个系统资源测试程序。程序里边使用了 Runtime 类关于系统资源的所有方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package cn.spads.test.grammar;
import java.util.LinkedList;
import java.util.Random;
/**
 * 本类用于示范使用 Runtime 检查系统运行情况。
 * 将 Runtime 作为可变成员,是为多系统公用检查预留的设计。
 * @author  Shane Loo Li
 */
public class PerformanceMonitor
{
    /**
     * 此量控制程序运行时间。此值越大,此演示程序运行时间越长。
     */
    static public int runLoopTimes = 55;
    /**
     * 此为每次检测间隔的时间片数。此值越大,间隔时间越长。
     */
    static public int waitTime = 1500000;
    static public void main(String[] arguments) throws Exception
    {
        Runtime context = Runtime.getRuntime();
        final PerformanceMonitor monitor = new PerformanceMonitor(context);
        final LinkedList<String> pretendedMemory = new LinkedList<String>();
        new Thread(
                new Runnable()
                {
                    public void run()
                    {
                        for (int j = -1; ++j != runLoopTimes; )
                        {
                            // 检查系统情况
                            monitor.checkAll();
                            // 每次检查运行情况之后,都会休息 1000 个时间片
                            for (int i = -1; ++i != waitTime; ) Thread.yield();
                            // 每次检查之后,会制造一些对象,记录其中一部分,并删除些老对象
                            for (int i = -1; ++i != 20000; )
                            {
                                StringBuilder builder = new StringBuilder();
                                Random ran = new Random();
                                for (int index = -1; ++index != 100; )
                                    builder.append((char) (ran.nextInt(26) + 64));
                                String garbage = new String(builder.toString());
                                garbage = garbage.substring(garbage.length());
                                pretendedMemory.add(builder.toString());
                            }
                            int deleteCount = new Random().nextInt(15000);
                            for (int i = -1; ++i != deleteCount; )
                                pretendedMemory.removeFirst();
                            System.out.println("-----------");
                        }
                    }
                }
            ).start();
    }
    private Runtime context;
    private double maxFreeMemory;
    private long lastFreeMemory;
    private long lastTotalMemory;
    private long lastMaxMemory;
    private double lastMemoryRate;
    public PerformanceMonitor(Runtime context)
    {
        this.context = context;
    }
    public void checkAll()
    {
        this.monitorMemory();
        this.monitorCpu();
    }
    /**
     * 本方法比较当前空余内存与历史记录最大空余内存的关系。若空余内存过小,则执行垃圾回收。
     */
    public void monitorMemory()
    {
        // 求空余内存,并计算空余内存比起最大空余内存的比例
        long freeMemory = this.context.freeMemory();
        if (freeMemory > this.maxFreeMemory)
            this.maxFreeMemory = Long.valueOf(freeMemory).doubleValue();
        double memoryRate = freeMemory / this.maxFreeMemory;
        System.out.println("There are " + memoryRate * 100 + "% free memory.");
        // 如果内存空余率在变小,则一切正常;否则需要报告内存变化情况
        if (memoryRate >= this.lastMemoryRate) this.reportMemoryChange();
        // 如果内存空余率很低,则执行内存回收
        if (freeMemory / this.maxFreeMemory < 0.3)
        {
            System.out.print("System will start memory Garbage Collection.");
            System.out.println(" Now we have " + freeMemory / 1000 + " KB free memory.");
            this.context.gc();
            System.out.println("After the Garbage Collection, we have "
                    + this.context.freeMemory() / 1000 + " KB free memory.");
        }
        // 记录内存信息
        this.recordMemoryInfo(memoryRate);
    }
    /**
     * 报告内存变化情况
     */
    private void reportMemoryChange()
    {
        System.out.print("Last freeMemory = " + this.lastFreeMemory / 1000 + " KB,");
        System.out.println(" now it is " + this.context.freeMemory() / 1000 + " KB.");
        System.out.print("Last totalMemory = " + this.lastTotalMemory / 1000 + " KB,");
        System.out.println(" now it is " + this.context.totalMemory() / 1000 + " KB.");
        System.out.print("Last maxMemory = " + this.lastMaxMemory / 1000 + " KB,");
        System.out.println(" now it is " + this.context.maxMemory() / 1000 + " KB.");
    }
    /**
     * 记录本次内存信息。
     */
    private void recordMemoryInfo(double memoryRate)
    {
        this.lastFreeMemory = this.context.freeMemory();
        this.lastMaxMemory = this.context.maxMemory();
        this.lastTotalMemory = this.context.totalMemory();
        this.lastMemoryRate = memoryRate;
    }
    /**
     * 监测 CPU 的方法。
     */
    public void monitorCpu()
    {
        int cpuCount = this.context.availableProcessors();
        if (cpuCount > 1) System.out.println("CPU have " + cpuCount + " processors.");
    }
}

我运行这段程序,得到结果报告。通过观察结果报告,我得到了一些新结论。
首先, maxMemory 在一台机器只运行一个爪哇(Java)虚拟机的前提下,一般来说并不会变动。
其次,新生代内存会很快地自动回收,这体现在 freeMemory 总是不断少量自动增加上。
最后,爪哇(Java)虚拟机会在内存不足时,自己申请新的内存。这个内存空间也能够根据报告大概看出一点原则:既不是完全通过可用内存比例,也不是完全通过可用内存数量。

我自己运行的报告附在下边

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
There are 100.0% free memory.
Last freeMemory = 0 KB, now it is 124371 KB.
Last totalMemory = 0 KB, now it is 126353 KB.
Last maxMemory = 0 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 79.91675736339026% free memory.
CPU have 8 processors.
-----------
There are 82.1353751773145% free memory.
Last freeMemory = 99921 KB, now it is 102695 KB.
Last totalMemory = 126353 KB, now it is 126353 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 100.0% free memory.
Last freeMemory = 102695 KB, now it is 140522 KB.
Last totalMemory = 126353 KB, now it is 159383 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 82.4930651724349% free memory.
CPU have 8 processors.
-----------
There are 65.90519105111919% free memory.
CPU have 8 processors.
-----------
There are 88.50612783993465% free memory.
Last freeMemory = 92611 KB, now it is 124371 KB.
Last totalMemory = 159383 KB, now it is 159383 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 71.68576727159902% free memory.
CPU have 8 processors.
-----------
There are 54.86540670326339% free memory.
CPU have 8 processors.
-----------
There are 100.0% free memory.
Last freeMemory = 77098 KB, now it is 172330 KB.
Last totalMemory = 159383 KB, now it is 225443 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 86.18976806966614% free memory.
CPU have 8 processors.
-----------
There are 72.37916940114857% free memory.
CPU have 8 processors.
-----------
There are 58.56890497502629% free memory.
CPU have 8 processors.
-----------
There are 46.292794574206056% free memory.
CPU have 8 processors.
-----------
There are 92.98754812452182% free memory.
Last freeMemory = 79776 KB, now it is 160245 KB.
Last totalMemory = 225443 KB, now it is 225443 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 79.17694945600425% free memory.
CPU have 8 processors.
-----------
There are 65.36668502988196% free memory.
CPU have 8 processors.
-----------
There are 51.556035296554015% free memory.
CPU have 8 processors.
-----------
There are 37.745845146519564% free memory.
CPU have 8 processors.
-----------
There are 23.935246478001996% free memory.
System will start memory Garbage Collection. Now we have 41247 KB free memory.
After the Garbage Collection, we have 312897 KB free memory.
CPU have 8 processors.
-----------
There are 100.0% free memory.
Last freeMemory = 312897 KB, now it is 292267 KB.
Last totalMemory = 380108 KB, now it is 380108 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 91.1770148111291% free memory.
CPU have 8 processors.
-----------
There are 84.11856206174096% free memory.
CPU have 8 processors.
-----------
There are 75.29548107031924% free memory.
CPU have 8 processors.
-----------
There are 68.2370940141088% free memory.
CPU have 8 processors.
-----------
There are 59.414100613590705% free memory.
CPU have 8 processors.
-----------
There are 52.35564786420257% free memory.
CPU have 8 processors.
-----------
There are 43.53256687278083% free memory.
CPU have 8 processors.
-----------
There are 34.70958168390994% free memory.
CPU have 8 processors.
-----------
There are 27.6511289345218% free memory.
System will start memory Garbage Collection. Now we have 80815 KB free memory.
After the Garbage Collection, we have 281843 KB free memory.
CPU have 8 processors.
-----------
There are 89.37604181852511% free memory.
Last freeMemory = 281843 KB, now it is 261217 KB.
Last totalMemory = 380108 KB, now it is 380108 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 80.55442250030752% free memory.
CPU have 8 processors.
-----------
There are 73.49712485596086% free memory.
CPU have 8 processors.
-----------
There are 64.67547542837015% free memory.
CPU have 8 processors.
-----------
There are 57.618177784023494% free memory.
CPU have 8 processors.
-----------
There are 48.79652835643279% free memory.
CPU have 8 processors.
-----------
There are 41.739230712086126% free memory.
CPU have 8 processors.
-----------
There are 32.91758128449542% free memory.
CPU have 8 processors.
-----------
There are 24.095931856904713% free memory.
System will start memory Garbage Collection. Now we have 70424 KB free memory.
After the Garbage Collection, we have 258135 KB free memory.
CPU have 8 processors.
-----------
There are 81.32306278893708% free memory.
Last freeMemory = 258135 KB, now it is 237681 KB.
Last totalMemory = 380108 KB, now it is 380108 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 72.5752415442342% free memory.
CPU have 8 processors.
-----------
There are 65.57687068029719% free memory.
CPU have 8 processors.
-----------
There are 56.828918049238894% free memory.
CPU have 8 processors.
-----------
There are 49.83056634581206% free memory.
CPU have 8 processors.
-----------
There are 41.08271772895181% free memory.
CPU have 8 processors.
-----------
There are 32.33487732373877% free memory.
CPU have 8 processors.
-----------
There are 25.33650645980177% free memory.
System will start memory Garbage Collection. Now we have 74050 KB free memory.
After the Garbage Collection, we have 229217 KB free memory.
CPU have 8 processors.
-----------
There are 71.73676393326296% free memory.
Last freeMemory = 229217 KB, now it is 209663 KB.
Last totalMemory = 380108 KB, now it is 380108 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------
There are 63.37379248412019% free memory.
CPU have 8 processors.
-----------
There are 55.01088399093938% free memory.
CPU have 8 processors.
-----------
There are 46.64788243242348% free memory.
CPU have 8 processors.
-----------
There are 38.28488087390758% free memory.
CPU have 8 processors.
-----------
There are 31.59450152482077% free memory.
CPU have 8 processors.
-----------
There are 23.231593031639967% free memory.
System will start memory Garbage Collection. Now we have 67898 KB free memory.
After the Garbage Collection, we have 203384 KB free memory.
CPU have 8 processors.
-----------
There are 61.86563040788292% free memory.
Last freeMemory = 203384 KB, now it is 180813 KB.
Last totalMemory = 380108 KB, now it is 380108 KB.
Last maxMemory = 1875378 KB, now it is 1875378 KB.
CPU have 8 processors.
-----------

我最近(2013-11-1 至 2013-11-25)参加了一个博客大赛。欢迎来给我投一票~
投票地址: http://blog.51cto.com/contest2013/5523233 每个用户每天可以投一票哦~

本文也发表在我的其他空间。
CSDN : http://blog.csdn.net/shanelooli/article/details/8176938
ITeye : http://surmounting.iteye.com/blog/1724328
开源中国: http://my.oschina.net/shane1984/blog/88803