应用DirectBuffer提升系统性能

Java 2 SE 6 doc :

Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer’s content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system’s native I/O operations.

  • DirectBuffer通过免去中间交换的内存拷贝, 提升IO处理速度;

Java 2 SE 6 doc :

The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious.

  • DirectBuffer-XX:MaxDirectMemorySize=xxM大小限制下[1], 使用Heap之外的内存, GC对此"无能为力"[2], 也就意味着规避了在高负载下频繁的GC过程对应用线程的中断影响.

因此, 当系统应用场景满足:

  • 大量原生类型数据使用
  • 频繁IO操作
  • 系统处理响应速度要求快且稳定

典型场景是网络数据传输, 可考虑合理应用DirectBuffer.

 

  1. MappedByteBuffer不受-XX:MaxDirectMemorySize=xxM大小限制.
  2. 下面的代码可验证程序运行中GC不尝试回收DirectBuffer:
  • 程序运行命令

 

 

 

java -XX:MaxDirectMemorySize=11M cn.cafusic.direct.buffer.gc.DirectBufferGCTest  <mode> <size>
  •   GC监控命令

 

jstat -gcutil <pid> 1000 60
  •  代码

 

package cn.cafusic.direct.buffer.gc;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel.MapMode;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * DirectBufferGCTest
 * 
 * @author <a href=mailto:[email protected]>jushi</a>
 * @created 2010-8-19
 * 
 */
public class DirectBufferGCTest {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(final String[] args) throws Exception {

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                running = false;
            }
        });

        final char mode = args[0].charAt(0);
        final int size = Integer.parseInt(args[1]);

        Callable<?> callable = null;
        switch (mode) {
            case RELEASE:
                callable = new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        final ByteBuffer[] buffers = new ByteBuffer[size];
                        int i = 0;
                        while (running) {
                            if (i == buffers.length) i = 0;
                            final ByteBuffer buffer = newBuffer(true);
                            buffers[i++] = buffer;
                            TimeUnit.SECONDS.sleep(1);
                        }
                        return null;
                    }

                };
                break;
            case HEAP:
                callable = new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        final ByteBuffer[] buffers = new ByteBuffer[size];
                        int i = 0;
                        while (running) {
                            if (i == buffers.length) i = 0;
                            final ByteBuffer buffer = newBuffer(false);
                            buffers[i++] = buffer;
                            TimeUnit.SECONDS.sleep(1);
                        }
                        return null;
                    }

                };
                break;
            case MAPPED:
                callable = new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        final RandomAccessFile file =
                            new RandomAccessFile("raf.test", "rw");
                        file.setLength(size * CAPACITY);
                        final MappedByteBuffer map =
                            file.getChannel().map(MapMode.READ_WRITE,
                                                  0,
                                                  file.length());
                        while (running) {
                            while (map.hasRemaining()) {
                                map.put((byte) 4);
                            }
                            map.clear();
                            TimeUnit.SECONDS.sleep(1);
                        }

                        file.close();
                        return null;
                    }

                };

                break;
            case KEEP:
                callable = new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        final ByteBuffer[] buffers = new ByteBuffer[size];
                        for (int i = 0; i < buffers.length; i++) {
                            buffers[i] = newBuffer(true);
                        }
                        while (running) {
                            TimeUnit.SECONDS.sleep(1);
                        }
                        return null;
                    }

                };

                break;

            default:
                throw new RuntimeException("error mode : " + mode);
        }

        callable.call();

    }

    static ByteBuffer newBuffer(final boolean direct) {
        final ByteBuffer buffer =
            direct ? ByteBuffer.allocateDirect(CAPACITY)
                : ByteBuffer.allocate(CAPACITY);
        while (buffer.hasRemaining()) {
            buffer.put((byte) 5);
        }
        return buffer;
    }

    private static final int CAPACITY = 1024 * 1024;

    private static final char HEAP = 'h';

    private static final char KEEP = 'k';

    private static final char MAPPED = 'm';

    private static final char RELEASE = 'r';

    private static boolean running = true;

}
 

 

你可能感兴趣的:(java,thread,网络应用)