直接内存

直接内存是Java程序的非常重要的组成部分,特别是NIO被广泛使用后,直接内存的使用也变得非常普遍。直接内存跳过了Java堆,使Java程序可以直接访问原生堆空间,因此一定程度的加快了内存空间的访问速度。这仅仅是读写上速度的优势,但是在内存分配时,就会存在劣势,下面我们将结合代码进行分析。

-XX:MaxDirectMemorySize设置最大直接可用内存

不设置则默认为最大堆空间(-Xmx指定)。当直接内存达到设定最大值时,就会触发GC,如果GC不能有效释放足够空间,就会引起OutOfMemeory错误。

读写速度的测试

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
public class AccessDirectBuffer {
public void directAccess(){
ByteBuffer b = ByteBuffer.allocateDirect(500); //先分配好空间,只对读写进行测试
long startTime = System.currentTimeMillis();
for(int i= 0;i<100000;i++){
for(int j = 0;j<100;j++)
b.putInt(j); //存100个数
b.flip();
for(int j = 0;j<100;j++)
b.getInt(j); //读100个数
}
long endTime = System.currentTimeMillis();
b.clear();
System.out.println("DirectAccess consume:"+(endTime-startTime));
}

public void bufferAccess(){
ByteBuffer b = ByteBuffer.allocate(500); //先分配好空间,只对读写进行测试
long startTime = System.currentTimeMillis();
for(int i= 0;i<100000;i++){
for(int j = 0;j<100;j++)
b.putInt(j); //存100个数
b.flip();
for(int j = 0;j<100;j++)
b.getInt(j); //读100个数
}
long endTime = System.currentTimeMillis();
b.clear();
System.out.println("DirectAccess consume:"+(endTime-startTime));
}

public static void main(String[] args) {
AccessDirectBuffer alloc = new AccessDirectBuffer();
alloc.bufferAccess();
alloc.directAccess();
alloc.bufferAccess();
alloc.directAccess();
}
}

BufferAccess consume:276
DirectAccess consume:130
BufferAccess consume:199
DirectAccess consume:64

可以看出直接内存访问比对堆内存访问快很多

使用-server(稍后会讲,虚拟机的工作模式)后,结果

BufferAccess consume:270
DirectAccess consume:115
BufferAccess consume:234
DirectAccess consume:58

直接内存被Server优化后,速度提升更加明显

内存分配测试

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
public class AllocDirectBuffer {
public void directAllocate(){
long startTime = System.currentTimeMillis();
for(int i= 0;i<100000;i++){
ByteBuffer b = ByteBuffer.allocateDirect(500);
}
long endTime = System.currentTimeMillis();
System.out.println("DirectAllocate consume:"+(endTime-startTime));
}

public void bufferAllocate(){
long startTime = System.currentTimeMillis();
for(int i= 0;i<100000;i++){
ByteBuffer b = ByteBuffer.allocate(500);
}
long endTime = System.currentTimeMillis();
System.out.println("BufferAllocate consume:"+(endTime-startTime));
}

public static void main(String[] args) {
AllocDirectBuffer alloc = new AllocDirectBuffer();
alloc.bufferAllocate();
alloc.directAllocate();
alloc.bufferAllocate();
alloc.directAllocate();
}
}

测试结果:

BufferAllocate consume:64
DirectAllocate consume:262
BufferAllocate consume:52
DirectAllocate consume:159

由此可见,在申请内存空间时,堆空间的速度远远高于直接内存

总结

直接内存适合请求分配内存次数,访问频繁的场合

如果内存空间需要频繁分配,则直接内存并不适合

虚拟机的两种工作模式

java虚拟机目前支持Client和Server两种运行模式,使用参数-Client和-Server指定。

使用java -version可以查看 当前模式

两者比较:

Server模式启动相对于Client模式来说较慢,因为Server模式会尝试手机更多的系统性能信息,使用更复杂的优化算法对程序进行优化。因此,当系统完全启动并进行运行稳定期后,Server模式的执行速度会远远快于Client模式。所以,对于后台长期运行的系统,使用-Server对性能提升帮助更大,对于用户界面程序,运行时间不长,又追求启动速度,Client更适合。