精华内容
下载资源
问答
  • 直接内存和堆内存谁快

    千次阅读 2018-05-30 08:25:35
    直接内存大多时候也被称为堆外内存,自从 JDK 引入 NIO 后,直接内存的使用也越来越普遍。通过 native 方法可以分配堆外内存,通过 DirectByteBuffer 对象来操作。 直接内存不属于 Java 堆,所以它不受堆大小限制,...

    前言

    直接内存大多时候也被称为堆外内存,自从 JDK 引入 NIO 后,直接内存的使用也越来越普遍。通过 native 方法可以分配堆外内存,通过 DirectByteBuffer 对象来操作。

    直接内存不属于 Java 堆,所以它不受堆大小限制,但是它受物理内存大小的限制。

    配置

    可以通过 -XX:MaxDirectMemorySize 参数来设置最大可用直接内存,如果启动时未设置则默认为最大堆内存大小,即与 -Xmx 相同。即假如最大堆内存为1G,则默认直接内存也为1G,那么 JVM 最大需要的内存大小为2G多一些。当直接内存达到最大限制时就会触发GC,如果回收失败则会引起OutOfMemoryError。

    分配内存耗时

    环境为JDK9,两种内存分配的耗时如下,运行两遍让其预热。可以看到直接内存的分配比较耗时,而堆内存分配操作耗时少好几倍。

    public static void directMemoryAllocate() {
            long tsStart = System.currentTimeMillis();
            for (int i = 0
    展开全文
  • 直接内存和堆内存 堆内存 直接内存(堆外内存) 零拷贝 NIO原生直接内存 直接内存的GC Netty的直接内存 在介绍Netty的内存管理前,先简单了解一下直接内存和堆内存 直接内存和堆内存 jvm中使用的内存可分为...

    目录

    直接内存和堆内存

    堆内存

    直接内存(堆外内存)

    零拷贝

    NIO原生直接内存

    直接内存的GC

    Netty的直接内存


    在介绍Netty的内存管理前,先简单了解一下直接内存和堆内存

    直接内存和堆内存

    jvm中使用的内存可分为两种,一个是堆内存,一个是直接内存。

    • 堆内存(HeapByteBuf)字节缓冲区:特点是内存的分配和回收速度快,可以被JVM自动回收;缺点就是如果进行Socket的IO读写,需要额外做一次内存复制,将堆内存对应的缓冲区复制到内核Channel中,性能会有一定程度的下降
    • 直接内存(DirectByteBuf) 字节缓冲区:非堆内存,它在对外进行内存分配,相比于堆内存,它的分配和回收速度会慢一些,但是将它写入或者从Socket Channel中读取时,由于少一次内存复制,速度比堆内存快

    直接内存和堆内存适用于不同的场景:

    • 在I/O通信线程的读写缓冲区使用DIrectByteBuf,可以减少一次jvm内存缓冲区到直接内存缓冲区的一次拷贝,可以从直接内存直接写入到Socket的缓冲区进行消息的发送。
    • 后端业务消息的编解码模块使用HeapByteBuf。

    堆内存

    堆内存是Jvm所管理的内存,相比方法区,栈内存,堆内存是最大的一块。所有的对象实例实例以及数组都要在堆上分配。Java的垃圾收集器是可以在堆上回收垃圾。

    java程序最大可能占用内存 = -Xmx指定的最大堆内存大小 + 最大活跃线程数量*-Xss指定的每个线程栈内存大小 + -XX:MaxDirectMemorySize指定的最大直接内存大小 + MetaSpace大小

    注意在Java8以后PermGen被MetaSpace代替,运行时可自动扩容,并且默认是无限大 

    直接内存(堆外内存)

    零拷贝

    这里的堆外内存特指的是java.nio.DirectByteBuffer或netty的DirectByteBuffer在创建的时候分配内存,之后通过Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。直接内存不会受到Java堆的限制,只受本机内存影响。

    零拷贝:使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。传统的堆内存(HEAP BUFFERS)进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入到Socket中。相比于堆外直接内存,消息在发送过程中多了一次缓冲区的内存拷贝。

    JDK内存拷贝代码位于sun.nio.ch.IOUtil.java:

    static int write(FileDescriptor var0, ByteBuffer var1, long var2, NativeDispatcher var4) throws IOException {
            if (var1 instanceof DirectBuffer) {
                return writeFromNativeBuffer(var0, var1, var2, var4);
            } else {
                int var5 = var1.position();
                int var6 = var1.limit();
    
                assert var5 <= var6;
    
                int var7 = var5 <= var6 ? var6 - var5 : 0;
                ByteBuffer var8 = Util.getTemporaryDirectBuffer(var7);
    
                int var10;
                try {
                    var8.put(var1);
                    var8.flip();
                    var1.position(var5);
                    int var9 = writeFromNativeBuffer(var0, var8, var2, var4);
                    if (var9 > 0) {
                        var1.position(var5 + var9);
                    }
    
                    var10 = var9;
                } finally {
                    Util.offerFirstTemporaryDirectBuffer(var8);
                }
    
                return var10;
            }
        }

    NIO原生直接内存

    在NIO中,所有数据都是用缓冲区处理的。读写数据,都是在缓冲区中进行的。缓存区实质是是一个数组,通常使用字节缓冲区——ByteBuffer。

    ByteBuffer可以申请两种方式的内存,分别为堆内存和直接内存:

    • ByteBuffer HeapbyteBuffer = ByteBuffer.allocate(1024);// 申请堆内存  
    • ByteBuffer DirectbyteBuffer = ByteBuffer.allocateDirect(1024);// 申请直接内存   

    直接内存的GC

    JVM中的直接内存,存在堆内存中其实就是DirectByteBuffer类,它本身其实很小,真的内存是在堆外,这里是映射关系。

    每次申请直接内存,都先看看是否超限 —— 直接内存的限额默认(可用 -XX:MaxDirectMemorySize 重新设定)。如果超过限额,就会主动执行System.gc(),这样会带来一个影响,系统会中断100ms。如果没有成功回收直接内存,并且还是超过直接内存的限额,就会抛出OOM——内存溢出。

    DirectByteBuffer熬过了几次young gc之后,会进入老年代。当老年代满了之后,会触发Full GC。

    因为本身很小,很难占满老年代,因此基本不会触发Full GC,带来的后果是大量堆外内存一直占着不放,无法进行内存回收。还有最后一个办法,就是依靠申请额度超限时触发的system.gc(),但是它会中断进程100ms,如果在这100ms的之间,系统未完成GC,仍会抛出OOM。

    Netty的直接内存

    Netty的ByteBuf是allocator分配的

    @Override
    public final void read() {
        final ChannelConfig config = config();
        if (shouldBreakReadReady(config)) {
            clearReadPending();
            return;
        }
        final ChannelPipeline pipeline = pipeline();
        // 获取allocator,allocator是创建ByteBuf对象
        final ByteBufAllocator allocator = config.getAllocator();
        final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
        allocHandle.reset(config);
    
        ByteBuf byteBuf = null;
        boolean close = false;
        try {
            do {
                // 从allocator获取一个ByteBuf对象实例
                byteBuf = allocHandle.allocate(allocator);
                // doReadBytes从底层socket读取数据到byteBuf
                allocHandle.lastBytesRead(doReadBytes(byteBuf));
                if (allocHandle.lastBytesRead() <= 0) {
                    // nothing was read. release the buffer.
                    byteBuf.release();
                    byteBuf = null;
                    close = allocHandle.lastBytesRead() < 0;
                    if (close) {
                        // There is nothing left to read as we received an EOF.
                        readPending = false;
                    }
                    break;
                }
    
                allocHandle.incMessagesRead(1);
                readPending = false;
                // 将byteBuf传给pipeline,从而开始数据处理
                pipeline.fireChannelRead(byteBuf);
                byteBuf = null;
            } while (allocHandle.continueReading());
    
            allocHandle.readComplete();
            pipeline.fireChannelReadComplete();
    
            if (close) {
                closeOnRead(pipeline);
            }
        } catch (Throwable t) {
            handleReadException(pipeline, byteBuf, t, close, allocHandle);
        } finally {
            // Check if there is a readPending which was not processed yet.
            // This could be for two reasons:
            // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
            // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
            //
            // See https://github.com/netty/netty/issues/2254
            if (!readPending && !config.isAutoRead()) {
                removeReadOp();
            }
        }
    }

    而allocator是从ChannelConfig中获取的

    final ByteBufAllocator allocator = config.getAllocator();

    所以allocator的实际类型代表了Channel具体是使用堆内存还是直接内存。这个可以通过用户代码通过childOption设置或者使用默认的:

    • 用户代码传入:主要是通过childOption传入,则ServerBootstrap在接收到客户端连接并创建SocketChannel时,会根据初始化ServerBootstrap时的childOption设置,对该SocketChannel的config进行配置。
    // 处理客户端请求的配置
    serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
    serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
    // 客户端SocketChannel所使用的allocator的实现类
    serverBootstrap.childOption(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT);
    serverBootstrap.childHandler(new NettyServerInitializer(webSocketService));
    
    • 默认实现,一般不需要通过用户代码传入,使用默认的即可,默认实现为:如果当前的运行平台是android,则使用unpooled,即不使用池化机制,因为android移动端,内存资源有限,不适合做缓存;其他平台则默认使用池化机制,提高性能,以空间换时间。其次是使用堆内存还是直接内存的问题,主要是根据:

    (1)当前运行平台是否支持使用Java的unsafe来进行本地方法调用;

    (2)程序的系统参数是否设置了io.netty.noPreferDirect=true。如果当前平台支持unsafe且io.netty.noPreferDirect=false或者没有设置,默认为false,则使用直接内存;否则使用堆内存。
    这两个参数的默认值:

    1. 是否运行通过底层api直接访问直接内存,默认:允许 
    -Dio.netty.noPreferDirect
    2. 是否允许使用sun.misc.Unsafe,默认:允许;注意:使用sun的私有类库存在平台移植问题,另外sun.misc.Unsafe类是不安全的,如果操作失败,不是抛出异常,而是虚拟机core dump,不建议使用Unsafe 
    -Dio.netty.noUnsafe
    

    DefaultChannelConfig 源码分析如下:

    1. 
    public class DefaultChannelConfig implements ChannelConfig {
        ...
        
        private volatile ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
        
        ...
    }
    
    2. 
    public interface ByteBufAllocator {
        
        ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
    }
    
    3. DEFAULT_ALLOCATOR
    public final class ByteBufUtil {
        ...
        
        static final ByteBufAllocator DEFAULT_ALLOCATOR;
    
        static {
            // android则是unpooled,其他为pooled
            String allocType = SystemPropertyUtil.get(
                    "io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
            allocType = allocType.toLowerCase(Locale.US).trim();
    
            ByteBufAllocator alloc;
            if ("unpooled".equals(allocType)) {
                alloc = UnpooledByteBufAllocator.DEFAULT;
                logger.debug("-Dio.netty.allocator.type: {}", allocType);
            } else if ("pooled".equals(allocType)) {
                alloc = PooledByteBufAllocator.DEFAULT;
                logger.debug("-Dio.netty.allocator.type: {}", allocType);
            } else {
                alloc = PooledByteBufAllocator.DEFAULT;
                logger.debug("-Dio.netty.allocator.type: pooled (unknown: {})", allocType);
            }
    
            DEFAULT_ALLOCATOR = alloc;
            
            ...
        }
    
        ...
    }
    
    4. UnpooledByteBufAllocator.DEFAULT:非池化机制默认alloctor
    /**
     * Default instance which uses leak-detection for direct buffers.
     */
    public static final UnpooledByteBufAllocator DEFAULT =
            new UnpooledByteBufAllocator(PlatformDependent.directBufferPreferred());
            
    5. PooledByteBufAllocator.DEFAULT:池化机制默认allocator
    public static final PooledByteBufAllocator DEFAULT =
            new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());
    
    6. 在4,5中,都调用了PlatformDependent.directBufferPreferred(),如果返回true,则使用直接内存,否则使用堆内存。PlatformDependent.directBufferPreferred()的底层实现如下:
    
    private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause0();
    private static final boolean DIRECT_BUFFER_PREFERRED =
            UNSAFE_UNAVAILABILITY_CAUSE == null && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
    
    unsafeUnavailabilityCause0的实现:判断当前平台是否支持使用Java的unsafe
    private static Throwable unsafeUnavailabilityCause0() {
        if (isAndroid()) {
            logger.debug("sun.misc.Unsafe: unavailable (Android)");
            return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (Android)");
        }
        Throwable cause = PlatformDependent0.getUnsafeUnavailabilityCause();
        if (cause != null) {
            return cause;
        }
    
        try {
            boolean hasUnsafe = PlatformDependent0.hasUnsafe();
            logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
            return hasUnsafe ? null : PlatformDependent0.getUnsafeUnavailabilityCause();
        } catch (Throwable t) {
            logger.trace("Could not determine if Unsafe is available", t);
            // Probably failed to initialize PlatformDependent0.
            return new UnsupportedOperationException("Could not determine if Unsafe is available", t);
        }
    }

    而Netty的ByteBuffer有实现了直接内存的子类,只需要在ChannelConfig中设置ByteBufAllocator申请buffer时申请直接内存就可以了。

    展开全文
  • Java直接内存原理

    千次阅读 2019-02-23 15:39:27
    直接内存 https://www.ibm.com/developerworks/library/j-nativememory-linux/index.html

    直接内存

    在这里插入图片描述在这里插入图片描述
    上述对直接内存的描述来自《深入理解Java虚拟机》,写明了直接内存不在java堆内,并且java堆内存往外写需要拷贝到native堆。

    然后咱们先写个代码看看直接内存分配在哪个区域

    import java.nio.ByteBuffer;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author congzhou
     * @description:
     * @date: Created in 2019/2/19 21:57
     */
    public class NativeHeapTest {
        public static void main(String[] args) throws InterruptedException {
            List<ByteBuffer> byteBufferList = new ArrayList<>();
            while (true) {
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(10240);
                byteBufferList.add(byteBuffer);
                Thread.sleep(100);
            }
        }
    }
    

    watch命令观察变化内存
    在这里插入图片描述
    我使用的是64位centos7,虚拟地址<00007fffffffffff 是用户空间内存[1]。ByteBuffer.allocateDirect()分配的是用户空间的匿名内存。

    再来看一下ByteBuffer.allocateDirect(int capacity)

    ByteBuffer.allocateDirect调用了Unsafe.allocateMemory(long var1),该方法是个native方法
    https://github.com/unofficial-openjdk/openjdk/blob/jdk/jdk/src/hotspot/share/prims/unsafe.cpp

    UNSAFE_ENTRY(jlong, Unsafe_AllocateMemory0(JNIEnv *env, jobject unsafe, jlong size)) {
      size_t sz = (size_t)size;
    
      sz = align_up(sz, HeapWordSize);
      void* x = os::malloc(sz, mtOther);
    
      return addr_to_java(x);
    } UNSAFE_END
    

    主要就是os::malloc(sz, mtInternal)方法,该方法封装了C++的标准库std::malloc()
    https://github.com/unofficial-openjdk/openjdk/blob/jdk/jdk/src/hotspot/share/runtime/os.cpp

    void* os::malloc(size_t size, MEMFLAGS flags) {
      return os::malloc(size, flags, CALLER_PC);
    }
    
    void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
    /*省略代码*/
      u_char* ptr;
      ptr = (u_char*)::malloc(alloc_size);
    /*省略代码*/
      // we do not track guard memory
      return MemTracker::record_malloc((address)ptr, size, memflags, stack, level);
    }
    

    (u_char*)::malloc(alloc_size)就是C++标准库函数,传入空间大小返回内存地址。

    那么堆内存怎么往外写

    openJDK sun.nio.ch.IOUtil.write(),java.nio.channels.SocketChannel#write(java.nio.ByteBuffer)等方法底层实现

    static int write(FileDescriptor fd, ByteBuffer src, long position,
                         NativeDispatcher nd)
            throws IOException
        {
            if (src instanceof DirectBuffer)
                return writeFromNativeBuffer(fd, src, position, nd);
    
            // Substitute a native buffer
            int pos = src.position();
            int lim = src.limit();
            assert (pos <= lim);
            int rem = (pos <= lim ? lim - pos : 0);
            ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
            try {
                bb.put(src);
                bb.flip();
                // Do not update src until we see how many bytes were written
                src.position(pos);
    
                int n = writeFromNativeBuffer(fd, bb, position, nd);
                if (n > 0) {
                    // now update src
                    src.position(pos + n);
                }
                return n;
            } finally {
                Util.offerFirstTemporaryDirectBuffer(bb);
            }
        }
    

    上述代码直观的展示了java堆内存首先拷贝到了直接内存,然后再把地址传给I/O函数。
    java GC三大类算法,除了标记清除,标记整理和复制算法都会移动对象,并且如果直接把java堆地址传给I/O函数则需要保证I/O操作过程中该块内存不变化,则需要暂停GC,所以JDK实现使用拷贝的方式。

    操作系统I/O过程中,需要把数据从用户态拷贝到内核态,然后再输出到I/O设备,所以从java堆内存输出到I/O设备需经过两次拷贝,而direct memory在native 堆上,所以只需经过一次拷贝。

    [1]https://www.kernel.org/doc/Documentation/x86/x86_64/mm.txt
    [2]https://www.linuxjournal.com/article/6345?page=0,1
    [3]https://www.ibm.com/developerworks/library/j-nativememory-linux/index.html
    [4]https://zhuanlan.zhihu.com/p/27625923
    [5]https://www.zhihu.com/question/57374068/answer/152691891

    展开全文
  • Java直接内存详解

    千次阅读 2017-12-10 10:46:17
    由于对直接内存的概念不是很清晰,所以查询了相关资料,准备一篇博文总结一下什么是直接内存直接内存(Direct Memory)就是Java堆外内存直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的...

    JVM直接内存

    前言

    在做欢聚时代的校招题时遇到了一道选择题,选项D如下:

    直接内存的分配不会受到Java堆大小的限制,所以不会抛OutOfMemoryError异常

    由于对直接内存的概念不是很清晰,所以查询了相关资料,准备一篇博文总结一下

    什么是直接内存

    直接内存(Direct Memory)就是Java堆外内存

    直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。

    在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。

    显然,本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。

    NIO代码实例

    NIO的Buffer提供一个可以直接访问系统物理内存的类——DirectBuffer。DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同。普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的 限制。而DirectBuffer直接分配在物理内存中,并不占用堆空间。在访问普通的ByteBuffer时,系统总是会使用一个“内核缓冲区”进行操作。而DirectBuffer所处的位置,就相当于这个“内核缓冲区”。因此,使用DirectBuffer是一种更加接近内存底层的方法,所以它的速度比普通的ByteBuffer更快。
    申请DirectBuffer代码如下:
    ByteBuffer.allocateDirect();
    下面,使用DirectBuffer和普通的ByteBuffer进行一段性能测试。

    DirectBuffer

    long start = System.currentTimeMillis();
            ByteBuffer buffer = ByteBuffer.allocateDirect(500);//分配500个字节的DirectBuffer
            for (int i = 0; i < 100000; i ++) {
                for (int j = 0; j < 99; j ++) {
                    buffer.putInt(j);           //向DirectBuffer写入数据
                }
                buffer.flip();
                for (int j = 0; j < 99; j ++) {
                    buffer.get();                   //从DirectBuffer中读取数据
                }
                buffer.clear();
            }
            System.out.println("DirectBuffer use : " + ( System.currentTimeMillis() - start ) + "ms");

    执行结果:
    DirectBuffer use : 20ms

    使用ByteBuffer:

    long start = System.currentTimeMillis();
            ByteBuffer buffer = ByteBuffer.allocate(500);//分配500个字节的ByteBuffer
            for (int i = 0; i < 100000; i ++) {
                for (int j = 0; j < 99; j ++) {
                    buffer.putInt(j);           //向DirectBuffer写入数据
                }
                buffer.flip();
                for (int j = 0; j < 99; j ++) {
                    buffer.get();                   //从DirectBuffer中读取数据
                }
                buffer.clear();
            }
            System.out.println("ByteBuffer use : " + ( System.currentTimeMillis() - start ) + "ms");

    执行结果:
    ByteBuffer use : 33ms
    以后两段测试代码分别使用了DirectBuffer和堆上的ByteBuffer,并进行了大量的读写访问。测试结果是DirectBuffer相对耗时20ms,而ByteBuffer相应耗时33ms.虽然都很快,但从比例上来说,DirectBuffer接近快了一倍。如果把外层的循环次数由10万改为100万,DirectBuffer use : 105ms,而ByteBuffer use : 225ms,快了一倍多。
    不过,虽然有访问速度上的优势,但是在创建和销毁DirectBuffer的花费却远比ByteBuffer高。

    for (int i = 0 ;i < 20000; i ++) {
                ByteBuffer b = ByteBuffer.allocateDirect(1000);
            }
            for (int i = 0 ;i < 20000; i ++) {
                ByteBuffer b = ByteBuffer.allocate(1000);
    }

    上面的两个for循环表示分别请求每种类型的Buffer 20M,设置运行时参数-XX:MaxDirectMemorySize=10M -Xmx10M,运行以下代码,使用DirectBuffer的代码段相对耗时297ms,而使用ByteBuffer的相对耗时仅15ms。因此可知,频繁的创建和销毁DirectBuffer远远大于在堆上分配内存空间。

    总结

    DirectBuffer的读写操作比普通Buffer快,但它的创建、销毁却比普通Buffer慢。

    展开全文
  • java 直接内存

    千次阅读 2016-03-11 17:24:58
    直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。...
  • JVM直接内存

    万次阅读 2018-01-03 15:40:40
    概述直接内存并不是虚拟机运行时数据区的一部分,也不是Java 虚拟机规范中农定义的内存区域。在JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O 方式,它可以使用...
  • 直接内存(堆外内存)

    千次阅读 2019-04-23 13:24:56
    Java中的内存分为两个部分,一部分是不需要jvm管理的直接内存,也被称为堆外内存。堆外内存就是把内存对象分配在JVM堆意外的内存区域,这部分内存不是虚拟机管理,而是由操作系统来管理,这样可以减少垃圾回收对应用...
  • 直接内存和堆内存的区别

    千次阅读 2018-05-26 21:04:55
    直接内存:NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer。 DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到...
  • JVM直接内存配置

    千次阅读 2018-08-17 22:38:04
    直接内存 -XX:MaxDirectMemorySize 设置直接内存 默认值,为最大堆空间大小,即-Xmx 直接内存达到上限时,会触发垃圾回收 如果,溢出,也会抛出OOM异常 应用在NIO中,跳过了Java堆 使程序可以直接访问,原生...
  • jvm堆外内存(直接内存)

    千次阅读 2018-11-27 21:04:46
    堆外内存(直接内存) 堆外内存,又被称为直接内存。这部分内存不是由jvm管理和回收的。需要我们手动的回收。 堆内内存是属于jvm的,由jvm进行分配和管理,属于"用户态",而推外内存是由操作系统管理的,...
  • jvm:堆外内存(直接内存

    千次阅读 2018-10-10 09:12:08
    堆内存根据生命周期进行分而治之,分区...HeapByteBuffer与DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap区域的,其实真正flush到远程的时候会先拷贝得到直接内存,再做下一步操作(考虑细节还会到...
  • 发现,由于直接内存被占满,一直在Full GC ,并且回收不掉,所以完全不处理玩家请求,通知运维重启服务器,临时解决。 2.考虑了下是不是把RPC连接数量改成了8条,超时改长了了导致,试着把数量减少,超时改成2个...
  • 堆外内存(直接内存)是否会被GC?

    千次阅读 2019-05-30 16:51:54
    堆外内存也被称为直接内存。 最近学习了有关于jvm内存区域的知识,想到了一个问题,堆内存会被GC,那堆外内存会被GC吗? https://www.jianshu.com/p/17e72bb01bf1?tdsourcetag=s_pcqq_aiomsg ...
  • RDMA(远程直接内存访问)技术浅析

    千次阅读 2017-10-26 10:52:29
    远程直接内存访问(即Remote Direct Memory Access)是一种直接内存访问技术,它将数据直接从一台计算机的内存传输到另一台计算机,无需双方操作系统的介入。
  • -----直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁地使用,而且可能导致OutOfMemoryError异常出现。 ----------在JDK1.4中新加入了NIO(New INput/...
  • HeapByteBuffer与DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap区域的,其实真正flush到远程的时候会先拷贝得到直接内存,再做下一步操作(考虑细节还会到OS级别的内核区直接内存),其实发送静态...
  • DMA(直接内存访问)

    千次阅读 2017-12-28 20:11:19
    DMA(直接内存访问)总结以往的io操作都需要经过cpu之手,在以前,cpu要一直轮询io系统,io操作是否已经结束,在这期间,cpu不能做其他的事情,效率极低,后来中断机制的出现,使得cpu的效率大大提高,主要的方法有...
  • Java直接内存分配与释放原理

    千次阅读 2019-04-02 11:15:54
    在Java中分配直接内存大有如下三种主要方式: 1.Unsafe.allocateMemory() 2.ByteBuffer.allocateDirect() 3.native方法 Unsafe类 Java提供了Unsafe类用来进行直接内存的分配与释放 public native long allocate...
  • JAVA直接内存(堆外内存)

    千次阅读 2019-03-25 13:57:05
    堆外内存介绍
  • Java直接内存读写的例子

    千次阅读 2014-08-31 22:02:42
    该类的allocateMemory方法用于申请分配内存,putAddress和getAddress方法用于对直接内存进行读写。  本文将通过sun.misc.Unsafe给出一个直接读写内存的例子。  注意:这只是一个例子,只是用来验证通过sun....
  • java直接内存与堆内存的比较

    千次阅读 2015-12-14 15:12:12
    对于nio这个库可以直接操作内存的使用,可以做个对比,看哪种情况下适合使用。import java.nio.ByteBuffer; public class AccessDirectBuffer { //直接分配内存 public static void directAccess() { long ...
  • jvm堆外直接内存实现高性能接入层

    千次阅读 2017-04-04 11:44:12
    接入层接受app的请求,解包数据重新封装数据包,把app数据包做为包... 为了性能上的保证,使用到netty的PooledDirectByteBuf,顾名思义就是池化的堆外直接内存,堆外直接内存就是jvm堆以外申请的内存,这里为什么考虑用
  • 直接内存访问(DMA)初探

    千次阅读 2013-12-12 14:55:18
    DMA(Direct Memory Access),直译为直接内存访问,是一种无需CPU的参与就可以让外设与系统内存之间进行双向数据传输的硬件机制。 使用DMA可以使系统CPU从实际的I/O数据传输过程中摆脱出来,从而大大提高系统的吞吐...
  • 为什么jdk1.8要把方法区从JVM里移到直接内存? 原因一:因为直接内存,JVM将会在IO操作上具有更高的性能,因为它直接作用于本地系统的IO操作。而非直接内存,也就是堆内存中的数据,如果要作IO操作,会先复制到直接...
  • Java直接内存访问的技巧

    千次阅读 2014-04-24 16:28:56
    Java被设计成一个安全,可管理的环境,然而 Java HotSpot有一个后门,提供了对低级别的,对直接内存和线程的操作。这个后门是—-sun.misc.Unsafe。这个类在JDK中有广泛的应用,例如,java.nio和java.util.concurrent...
  • Java直接内存和堆内存的性能比较

    千次阅读 2016-09-08 11:17:06
    它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。 这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数
  • Java如何使用直接内存

    千次阅读 2021-05-11 23:41:04
    写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者...它可以使用Native函数库直接分配堆外内存,然后通过个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。 这样能在一些场景中显
  • 堆外内存(直接内存

    万次阅读 多人点赞 2016-08-25 17:37:44
    direct缓冲区使用的内存,绕过了JVM堆,通过本地代码调用分配。创建和销毁都要比驻留在JVM堆里的缓冲区更加耗时(依赖于操作系统和JVM实现)。direct缓冲区使用的内存不受垃圾收集的控制,因为它们在JVM堆的外部。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,301,647
精华内容 920,658
关键字:

直接内存