无题
无题
John Doejava直接内存分配的原理分析
1. java的内存布局
众所周知,java中对象的创建都是基于java堆进行的,如下为java的内存结构
2. java对象内存布局
java对象在堆内存中的内存布局如下所示,分别显示了java 的对象和数组对象的内存结构
对于java对象实例,其都是存储在java堆中的,接下来我们说明这个问题,对于直接操作内存,我们需要获取Unsafe对象
1 | private static Unsafe unsafe; |
引入jol依赖,利用jol获取对象实例地址,由于关闭了类指针压缩,所以字节数组的数据部分相对实例地址的位置偏移了24字节,通过unsafe对象直接获取该内存中的值,即可获取堆内存中数组array的各个值,答应如下,实现对内存的直接操作
1 | byte[] array = new byte[]{66, 77, 88, 99}; |
输出结果:
0 : 66
1 : 77
2 : 88
3 : 99
上面展示的案例安全吗?必定是不安全的,因为对java堆了解的人都知道,堆区的对象为了垃圾回收是在一直移动的,所以直接对内存的十分危险,下面举例说明
1 | byte[] array = new byte[]{66, 77, 88, 99}; |
得出的结果如下:
垃圾回收前数组array地址 : 711e71998
垃圾回收后数组array地址 : 703a07828
可以看出回收前和回收后的地址发生了变化,所以在堆区对内存的操作十分危险,可能会影响到其他堆区的对象
3. java直接内存
java中有直接对内存操作的对象DirectByteBuffer,何为直接内存,就是脱离堆区的控制,防止垃圾回收对地址产生影响,可以理解为其就是c和c++中堆内存的分配
在Java中,底层都是通过 Unsafe#allocateMemory 分配直接内存,所以直接看该函数的原理即可
经过一系列调用,最终会调用native方法 Unsafe#allocateMemory0,通过阅读该部分的 c++源码,如下
1 | UNSAFE_LEAF(jlong, Unsafe_AllocateMemory0(JNIEnv *env, jobject unsafe, jlong size)) { |
可以看到底层也是调用了操作系统的malloc函数进行内存的申请,而操作系统不同对于malloc的实现也不同,下面简单介绍一下linux下的底层实现
malloc函数在linux系统中底层在是通过brk()和mmap() 来实现内存的分配,当分配的内存大于128K时,调用**mmap()函数在Memory Mapping Region内存映射器内进行内存分配,创建匿名的虚拟文件的内存映射;否则调用brk()**函数在Heap堆区进行内存分配



